webpack.prod.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import PreloadPlugin from '@vue/preload-webpack-plugin';
  2. // import { version as axiosVersion } from 'axios/package.json';
  3. import CompressionPlugin from 'compression-webpack-plugin';
  4. import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
  5. import HtmlWebpackTagsPlugin from 'html-webpack-tags-plugin';
  6. import MiniCssExtractPlugin from 'mini-css-extract-plugin';
  7. // import { version as piniaVersion } from 'pinia/package.json';
  8. import TerserPlugin from 'terser-webpack-plugin';
  9. // import { version as vueDemiVersion } from 'vue-demi/package.json';
  10. // import { version as vueRouterVersion } from 'vue-router/package.json';
  11. // import { version as vueVersion } from 'vue/package.json';
  12. import { Configuration } from 'webpack';
  13. import WebpackBar from 'webpackbar';
  14. import { gzipEnable } from '../constant';
  15. import { chalkINFO } from '../utils/chalkTip';
  16. console.log(chalkINFO(`读取: ${__filename.slice(__dirname.length + 1)}`));
  17. const prodConfig: Configuration = {
  18. mode: 'production',
  19. devtool: false,
  20. // externals: {
  21. // vue: 'Vue',
  22. // 'vue-router': 'VueRouter',
  23. // pinia: 'Pinia',
  24. // axios: 'axios',
  25. // },
  26. optimization: {
  27. /**
  28. * splitChunks属性,如果设置了mode: 'production',会有默认行为,具体看官网
  29. * 但即使没有设置mode: 'production',也没有手动添加splitChunks属性,默认还是会添加splitChunks的部分行为,
  30. * 比如:splitChunks.chunks:'async'等等,即会将异步代码抽离!
  31. */
  32. splitChunks: {
  33. // 对入口文件进行代码分离
  34. // chunks: 'all', //async,initial,all
  35. // minSize: 20 * 1024, //生成 chunk 的最小体积。默认:20000(19.5kb)
  36. /**
  37. * maxSize:尝试将大于maxSize的chunk分割成较小的部分chunks。
  38. * 官网写的默认值是0,但是,实际测试:如果在chunks:async的时候,确实这个属性会生效,会将异步代码配合minSize进行抽离;
  39. * 但是如果在chunks:initial或all的时候,如果不手动添加maxSize属性,就不会将同步代码配合minSize进行抽离!
  40. * 因此,如果希望maxSize可以对同步和异步代码都进行分离,就手动设置maxSize:0,或者手动设置maxSize为自己需要设置的值,
  41. * 但一定不能不写这个maxSize!最起码也得写一个maxSize:0,虽然这样写会报警告,或者直接写maxSize的值和minSize值一样!
  42. */
  43. // maxSize: 0, //不写maxSize默认就是0,这里手动设置0
  44. // maxSize: 30 * 1024,
  45. // minRemainingSize: 0, //???
  46. // minChunks: 1, //模块被不同entry引用的次数大于等于才能分割。
  47. // maxAsyncRequests: 30, //按需加载时的最大并行请求数。默认:30
  48. // maxInitialRequests: 30, //按需加载时的最大并行请求数。默认:30
  49. /**
  50. * enforceSizeThreshold:强制执行拆分的体积阈值和其他限制(minRemainingSize,maxAsyncRequests,maxInitialRequests)将被忽略。
  51. * 即拆分的包大小范围允许在这个阈值范围,即设置minSize:20 * 1024,enforceSizeThreshold: 10 * 1024,
  52. * 允许拆分的包在10kb-30kb之间!
  53. */
  54. // enforceSizeThreshold: 1 * 1024, //默认:50000byte
  55. /**
  56. * 不建议全局设置filename,因为如果缓存组没有手动设置filename,默认缓存组会继承全局
  57. * 的filename,这样在某些情况会显得很奇葩,比如:全局设置了chunks:'async',filename:'[id]-asyncChunks.js',
  58. * 而缓存组设置了一个chunks:'initial',且没有设置它的filename,那么最终打包会先匹配缓存组,然后匹配
  59. * 到同步代码就抽离,然后设置filename,由于这个缓存组没有设置它的filename,因此会继承全局的filename,
  60. * 因此就会把同步代码抽离后叫[id]-asyncChunks.js,虽然还是一样把代码抽离出来了,但是
  61. * 抽离出来的文件和文件名"货不对板",做不到见名知意,这样就很别扭了。因此如果设置设置了全局的filename,那
  62. * 么最好就是每一个缓存组都设置自己的filename,这样就可以和全局的进行区分了
  63. */
  64. // filename: "[id]-splitChunks.js", //默认[name]-bundle.js
  65. /**
  66. * 缓存组可以继承和/或覆盖来自 splitChunks.* 的任何选项
  67. * 即如果匹配到缓存缓存组里的某一个,如vendor,vendor里的设置会对splitChunks的设置进行继承或覆盖
  68. * 即vendor里没有设置chunks,vendor就会继承splitChunks的chunks,vendor设置了filename,会覆盖splitChunks的filename
  69. */
  70. cacheGroups: {
  71. // cacheGroups里的优先级默认比外面的高
  72. // defaultVendors:false, //禁用默认webpack默认设置的defaultVendors缓存组
  73. // default:false, //禁用默认webpack默认设置的default缓存组
  74. defaultVendors: {
  75. // 重写默认的defaultVendors
  76. chunks: 'initial',
  77. // minSize: 50 * 1024,
  78. maxSize: 100 * 1024,
  79. test: /[\\/]node_modules[\\/]/,
  80. // filename: 'js/[name]-defaultVendors.js',
  81. filename: 'js/[name]-[contenthash:6]-defaultVendors.js',
  82. priority: -10,
  83. },
  84. default: {
  85. // 重写默认的default
  86. chunks: 'all',
  87. maxSize: 100 * 1024,
  88. filename: 'js/[name]-[contenthash:6]-default.js',
  89. minChunks: 2, // 至少被minChunks个入口文件引入了minChunks次。
  90. priority: -20,
  91. },
  92. },
  93. },
  94. usedExports: true, // production模式或者不设置usedExports,它默认就是true。usedExports的目的是标注出来哪些函数是没有被使用 unused,会结合Terser进行处理
  95. sideEffects: true, // webpack.dev.ts有注释
  96. minimize: true, // 是否开启Terser,默认就是true,设置false后,不会压缩和转化
  97. minimizer: [
  98. new TerserPlugin({
  99. parallel: true, // 使用多进程并发运行以提高构建速度
  100. extractComments: false, // 默认true,会将/^\**!|@preserve|@license|@cc_on/i的注释提取到单独的文件中
  101. // Terser 压缩配置
  102. terserOptions: {
  103. parse: {
  104. // 注意:terserOptions.parse被标记了deprecated。
  105. },
  106. compress: {
  107. // defaults:true,默认true,传递false禁用大多数默认启用的compress转换
  108. arguments: true, // 默认false,尽可能将参数[index]替换为函数参数名
  109. dead_code: true, // 默认true,删除无法访问的代码(比如return后面的语句)
  110. toplevel: false, // 默认false,在顶级作用域中删除未引用的函数("funcs")和/或变量("vars"), 设置true表示同时删除未引用的函数和变量
  111. keep_classnames: false, // 默认false,传递true以防止terser丢弃类名
  112. keep_fnames: false, // 默认false,传递true以防止terser丢弃函数名
  113. drop_console: false, // 默认false,设置true会删掉丢掉对console.*函数的调用
  114. // pure_funcs: ['console.log'], // 告诉terser,console.log没有副作用,terser会将它删除
  115. },
  116. /**
  117. * mangle,默认值true,会将keep_classnames,keep_fnames,toplevel等等mangle options的所有选项设为true。
  118. * 传递false以跳过篡改名称,或者传递一个对象来指定篡改选项
  119. */
  120. mangle: true,
  121. toplevel: false, // 注意:terserOptions.toplevel被标记了deprecated。默认false,如果希望启用顶级变量和函数名修改,并删除未使用的变量和函数,则设置为true。
  122. keep_classnames: true, // 默认undefined,传递true以防止丢弃或混淆类名。
  123. keep_fnames: false, // 默认false,传递true以防止函数名被丢弃或混淆。
  124. // TODO 外层的keep_classnames和keep_fnames和compress的有啥区别or优先级?
  125. },
  126. }),
  127. new CssMinimizerPlugin({
  128. parallel: true, // 使用多进程并发执行,提升构建速度。
  129. }), // css压缩,去除无用的空格等等
  130. ],
  131. // runtimeChunk: {
  132. // name: 'runtime'
  133. // }
  134. },
  135. // module: {
  136. // rules: [
  137. // {
  138. // test: /\.jsx?$/,
  139. // exclude: /node_modules/,
  140. // use: [
  141. // // 'thread-loader',
  142. // {
  143. // loader: 'babel-loader',
  144. // options: {
  145. // cacheDirectory: true,
  146. // cacheCompression: false, // https://github.com/facebook/create-react-app/issues/6846
  147. // },
  148. // },
  149. // ],
  150. // },
  151. // {
  152. // test: /\.tsx?$/,
  153. // exclude: /node_modules/,
  154. // use: [
  155. // {
  156. // loader: 'babel-loader',
  157. // options: {
  158. // cacheDirectory: true,
  159. // cacheCompression: false, // https://github.com/facebook/create-react-app/issues/6846
  160. // },
  161. // },
  162. // {
  163. // loader: 'ts-loader',
  164. // options: {
  165. // appendTsxSuffixTo: ['\\.vue$'],
  166. // // If you want to speed up compilation significantly you can set this flag. https://www.npmjs.com/package/ts-loader#transpileonly
  167. // transpileOnly: true,
  168. // happyPackMode: false,
  169. // },
  170. // },
  171. // ],
  172. // },
  173. // ],
  174. // },
  175. plugins: [
  176. // 构建进度条
  177. new WebpackBar(),
  178. // http压缩
  179. gzipEnable &&
  180. new CompressionPlugin({
  181. test: /\.(css|js)$/i,
  182. threshold: 10 * 1024, // 大于10k的文件才进行压缩
  183. minRatio: 0.8, // 只有压缩比这个比率更好的资产才会被处理(minRatio =压缩大小/原始大小),即压缩如果达不到0.8就不会进行压缩
  184. algorithm: 'gzip', // 压缩算法
  185. }),
  186. // 注入script或link
  187. new HtmlWebpackTagsPlugin({
  188. append: false,
  189. publicPath: '', // 默认会拼上output.publicPath,因为我们引入的是cdn的地址,因此不需要拼上output.publicPath,直接publicPath:'',这样就约等于拼上空字符串''
  190. links: [],
  191. // scripts: [
  192. // `https://unpkg.com/vue@${vueVersion}/dist/vue.global.prod.js`,
  193. // `https://unpkg.com/vue-router@${vueRouterVersion}/dist/vue-router.global.prod.js`,
  194. // `https://unpkg.com/axios@${axiosVersion}/dist/axios.min.js`,
  195. // `https://unpkg.com/vue-demi@${vueDemiVersion}/lib/index.iife.js`,
  196. // `https://unpkg.com/pinia@${piniaVersion}/dist/pinia.iife.prod.js`,
  197. // ],
  198. }),
  199. // 将 CSS 提取到单独的文件中
  200. new MiniCssExtractPlugin({
  201. /**
  202. * Options similar to the same options in webpackOptions.output
  203. * all options are optional
  204. */
  205. filename: 'css/[name]-[contenthash:6].css',
  206. chunkFilename: 'css/[id]-[contenthash:6].css',
  207. ignoreOrder: false, // Enable to remove warnings about conflicting order
  208. }),
  209. // Css TreeShaking
  210. // new PurgeCssPlugin({
  211. // /**
  212. // * 实际测试有一些bug,比如html里面有ul这个元素,css里面的.ul{},#ul{},ul{}都会打包进去???
  213. // * 在js文件里如果有给元素添加类,但是注释了,如:// divEle.className='test123',但是这个.test123一样会打包进去,得手动删除这行注释代码才行!
  214. // * 而且貌似不能对.vue文件进行treeShaking,而且构建出来的css文件会空白,没有任何内容,所以暂时不用这个插件了
  215. // */
  216. // paths: glob.sync(`${path.resolve(__dirname, '../src')}/**/*`, {
  217. // nodir: true,
  218. // }),
  219. // safelist: function () {
  220. // return {
  221. // standard: ['body', 'html'],
  222. // };
  223. // },
  224. // }),
  225. // 预加载
  226. new PreloadPlugin({
  227. rel: 'preload',
  228. include: 'initial',
  229. fileBlacklist: [/\.map$/, /hot-update\.js$/],
  230. }),
  231. // 预获取
  232. new PreloadPlugin({
  233. rel: 'prefetch',
  234. include: 'asyncChunks',
  235. }),
  236. // new webpack.optimize.ModuleConcatenationPlugin(), //作用域提升。!!!在使用cdn时,axios有问题,先不用!
  237. ].filter(Boolean),
  238. };
  239. export default prodConfig;