webpack.prod.ts 12 KB

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