webpack.prod.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. const webpack = require('webpack')
  2. const path = require('path')
  3. const fs = require('fs-extra')
  4. const yargs = require('yargs').argv
  5. const _ = require('lodash')
  6. const Fiber = require('fibers')
  7. const { VueLoaderPlugin } = require('vue-loader')
  8. const { CleanWebpackPlugin } = require('clean-webpack-plugin')
  9. const CopyWebpackPlugin = require('copy-webpack-plugin')
  10. const HtmlWebpackPlugin = require('html-webpack-plugin')
  11. const HtmlWebpackPugPlugin = require('html-webpack-pug-plugin')
  12. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  13. const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
  14. const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
  15. const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
  16. const WebpackBarPlugin = require('webpackbar')
  17. const SriWebpackPlugin = require('webpack-subresource-integrity')
  18. const babelConfig = fs.readJsonSync(path.join(process.cwd(), '.babelrc'))
  19. const cacheDir = '.webpack-cache/cache'
  20. const babelDir = path.join(process.cwd(), '.webpack-cache/babel')
  21. process.noDeprecation = true
  22. fs.emptyDirSync(path.join(process.cwd(), 'assets'))
  23. module.exports = {
  24. mode: 'production',
  25. entry: {
  26. app: './client/index-app.js',
  27. legacy: './client/index-legacy.js',
  28. setup: './client/index-setup.js'
  29. },
  30. output: {
  31. path: path.join(process.cwd(), 'assets'),
  32. publicPath: '/',
  33. filename: 'js/[name].[hash].js',
  34. chunkFilename: 'js/[name].[chunkhash].js',
  35. globalObject: 'this',
  36. crossOriginLoading: 'use-credentials'
  37. },
  38. module: {
  39. rules: [
  40. {
  41. test: /\.js$/,
  42. exclude: (modulePath) => {
  43. return modulePath.includes('node_modules') && !modulePath.includes('vuetify')
  44. },
  45. use: [
  46. {
  47. loader: 'cache-loader',
  48. options: {
  49. cacheDirectory: cacheDir
  50. }
  51. },
  52. {
  53. loader: 'babel-loader',
  54. options: {
  55. ...babelConfig,
  56. cacheDirectory: babelDir
  57. }
  58. }
  59. ]
  60. },
  61. {
  62. test: /\.css$/,
  63. use: [
  64. 'style-loader',
  65. MiniCssExtractPlugin.loader,
  66. 'css-loader',
  67. 'postcss-loader'
  68. ]
  69. },
  70. {
  71. test: /\.sass$/,
  72. use: [
  73. {
  74. loader: 'cache-loader',
  75. options: {
  76. cacheDirectory: cacheDir
  77. }
  78. },
  79. 'style-loader',
  80. 'css-loader',
  81. 'postcss-loader',
  82. {
  83. loader: 'sass-loader',
  84. options: {
  85. implementation: require('sass'),
  86. fiber: Fiber,
  87. sourceMap: false
  88. }
  89. }
  90. ]
  91. },
  92. {
  93. test: /\.scss$/,
  94. use: [
  95. {
  96. loader: 'cache-loader',
  97. options: {
  98. cacheDirectory: cacheDir
  99. }
  100. },
  101. 'style-loader',
  102. MiniCssExtractPlugin.loader,
  103. 'css-loader',
  104. 'postcss-loader',
  105. {
  106. loader: 'sass-loader',
  107. options: {
  108. implementation: require('sass'),
  109. fiber: Fiber,
  110. sourceMap: false
  111. }
  112. },
  113. {
  114. loader: 'sass-resources-loader',
  115. options: {
  116. resources: path.join(process.cwd(), '/client/scss/global.scss')
  117. }
  118. }
  119. ]
  120. },
  121. {
  122. test: /\.vue$/,
  123. loader: 'vue-loader'
  124. },
  125. {
  126. test: /\.pug$/,
  127. exclude: [
  128. path.join(process.cwd(), 'dev')
  129. ],
  130. loader: 'pug-plain-loader'
  131. },
  132. {
  133. test: /\.(png|jpg|gif)$/,
  134. use: [
  135. {
  136. loader: 'url-loader',
  137. options: {
  138. limit: 8192
  139. }
  140. }
  141. ]
  142. },
  143. {
  144. test: /\.svg$/,
  145. exclude: [
  146. path.join(process.cwd(), 'node_modules/grapesjs')
  147. ],
  148. use: [
  149. {
  150. loader: 'file-loader',
  151. options: {
  152. name: '[name].[ext]',
  153. outputPath: 'svg/'
  154. }
  155. }
  156. ]
  157. },
  158. {
  159. test: /\.(graphql|gql)$/,
  160. exclude: /node_modules/,
  161. use: [
  162. { loader: 'graphql-persisted-document-loader' },
  163. { loader: 'graphql-tag/loader' }
  164. ]
  165. },
  166. {
  167. test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
  168. exclude: [
  169. path.join(process.cwd(), 'client')
  170. ],
  171. use: [{
  172. loader: 'file-loader',
  173. options: {
  174. name: '[name].[ext]',
  175. outputPath: 'fonts/'
  176. }
  177. }]
  178. },
  179. {
  180. test: /.jsx$/,
  181. loader: 'babel-loader',
  182. exclude: /node_modules/,
  183. options: {
  184. presets: ['es2015', 'react']
  185. }
  186. },
  187. {
  188. test: /\.flow$/,
  189. loader: 'ignore-loader'
  190. }
  191. ]
  192. },
  193. plugins: [
  194. new VueLoaderPlugin(),
  195. new VuetifyLoaderPlugin(),
  196. new webpack.BannerPlugin('Wiki.js - wiki.js.org - Licensed under AGPL'),
  197. new CopyWebpackPlugin([
  198. { from: 'client/static' },
  199. { from: './node_modules/prismjs/components', to: 'js/prism' },
  200. { from: './node_modules/graphql-voyager/dist/voyager.worker.js', to: 'js/' }
  201. ], {}),
  202. new MiniCssExtractPlugin({
  203. filename: 'css/bundle.[hash].css',
  204. chunkFilename: 'css/[name].[chunkhash].css'
  205. }),
  206. new HtmlWebpackPlugin({
  207. template: 'dev/templates/master.pug',
  208. filename: '../server/views/master.pug',
  209. hash: false,
  210. inject: false,
  211. excludeChunks: ['setup', 'legacy']
  212. }),
  213. new HtmlWebpackPlugin({
  214. template: 'dev/templates/legacy.pug',
  215. filename: '../server/views/legacy/master.pug',
  216. hash: false,
  217. inject: false,
  218. excludeChunks: ['setup', 'app']
  219. }),
  220. new HtmlWebpackPlugin({
  221. template: 'dev/templates/setup.pug',
  222. filename: '../server/views/setup.pug',
  223. hash: false,
  224. inject: false,
  225. excludeChunks: ['app', 'legacy']
  226. }),
  227. new HtmlWebpackPugPlugin(),
  228. new ScriptExtHtmlWebpackPlugin({
  229. sync: 'runtime.js',
  230. defaultAttribute: 'async'
  231. }),
  232. new SriWebpackPlugin({
  233. hashFuncNames: ['sha256', 'sha512'],
  234. enabled: true
  235. }),
  236. new WebpackBarPlugin({
  237. name: 'Client Assets'
  238. }),
  239. new CleanWebpackPlugin(),
  240. new OptimizeCssAssetsPlugin({
  241. cssProcessorOptions: { discardComments: { removeAll: true } },
  242. canPrint: true
  243. }),
  244. new webpack.DefinePlugin({
  245. 'process.env.NODE_ENV': JSON.stringify('production'),
  246. 'process.env.CURRENT_THEME': JSON.stringify(_.defaultTo(yargs.theme, 'default')),
  247. '__REACT_DEVTOOLS_GLOBAL_HOOK__': '({ isDisabled: true })'
  248. })
  249. ],
  250. optimization: {
  251. namedModules: true,
  252. namedChunks: true,
  253. splitChunks: {
  254. name: 'vendor',
  255. minChunks: 2
  256. },
  257. runtimeChunk: 'single'
  258. },
  259. resolve: {
  260. mainFields: ['browser', 'main', 'module'],
  261. symlinks: true,
  262. alias: {
  263. '@': path.join(process.cwd(), 'client'),
  264. 'vue$': 'vue/dist/vue.esm.js',
  265. 'gql': path.join(process.cwd(), 'client/graph'),
  266. // Duplicates fixes:
  267. 'apollo-link': path.join(process.cwd(), 'node_modules/apollo-link'),
  268. 'apollo-utilities': path.join(process.cwd(), 'node_modules/apollo-utilities'),
  269. 'uc.micro': path.join(process.cwd(), 'node_modules/uc.micro')
  270. },
  271. extensions: [
  272. '.js',
  273. '.json',
  274. 'jsx',
  275. '.vue'
  276. ],
  277. modules: [
  278. 'node_modules'
  279. ]
  280. },
  281. node: {
  282. fs: 'empty'
  283. },
  284. stats: {
  285. children: false,
  286. entrypoints: false
  287. },
  288. target: 'web'
  289. }