module.exports = { module: { rules: [ { test: /.(|ts|tsx|js|jsx)$/, // 只解析 src 文件夹下的 ts、tsx、js、jsx 文件 // include 可以是数组,表示多个文件夹下的模块都要解析 include: path.resolve(__dirname, '../src'), use: [ 'thread-loader', 'babel-loader'], // 堆代码 duidaima.com //当然也可以配置 exclude,表示 loader 解析时不会编译这部分文件 //同样 exclude 也可以是数组 exclude: /node_modules/, } ] } }还需注意一个点就是要确保 loader 的准确性,比如不要使用 less-loader 去解析 css 文件。
module.export = { resolve: { // 按照 tsx、ts、jsx、js 的顺序匹配,若没匹配到则报错 extensions: ['.tsx', '.ts', '.jsx', '.js'], } }别名
module.exports = { resolve: { alias: { //把 src 文件夹别名为 @ //引入 src 下的文件就可以 import xxx from '@/xxx' '@': path.join(__dirname, '../src') } } } // 引入 src 下的某个模块时 import XXX from '@/xxx/xxx.tsx'缓存
module.exports = { module: { rules: [ { test: /.jsx?$/, use: [ { loader: 'babel-loader', options: { cacheDirectory: true, }, } ] } ] } }当我们编译后,会在 /node_modules/.cache/babel-loader 产生对应的缓存文件夹,在下一次编译时,将会尝试读取缓存来避免在每次执行时,可能产生的、高性能消耗的编译过程
module.exports = { module: { rules: [ { test: /.jsx?$/, use: [ 'cache-loader', "babel-loader" ], } ] } }编译后同样多一个 /node_modules/.cache/cache-loader 缓存目录
module.exports = { cache: { type: 'filesystem' } }编译后会多出 /node_modules/.cache/webpack 缓存目录
module.exports = { module: { rules: [ { test: /.jsx?$/, use: [ // 开启多进程打包。 { loader: 'thread-loader', options: { workers: 3 // 开启 3个 进程 } }, { loader: 'babel-loader', } ] } ] } }放置在这个 thread-loader 之后的 loader 就会在一个单独的 worker 池(worker pool) 中运行。每个 worker 都是一个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。所以建议仅在耗时的 loader 上使用。若项目文件不算多就不要使用,毕竟开启多个线程也会存在性能开销。
module.export = { resolve: { modules: [path.resolve(__dirname, 'node_modules')] } }构建结果优化
const TerserPlugin = require('terser-webpack-plugin'); module.exports = { optimization: { // 开启压缩 minimize: true, // 压缩工具 minimizer: [ new TerserPlugin({}), ], }, }需要注意一个地方:生产环境会默认配置terser-webpack-plugin,所以如果你还有其它压缩插件使用的话需要将TerserPlugin显示配置或者使用...,否则terser-webpack-plugin会被覆盖。
const TerserPlugin = require("terser-webpack-plugin"); optimization: { minimize: true, minimizer: [ new TerserPlugin({}), // 显示配置 // "...", // 或者使用展开符,启用默认插件 // 其它压缩插件 new CssMinimizerPlugin(), ], },压缩 css
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); module.exports = { module: { rules: [ { test: /.css$/, use: [ // 堆代码 duidaima.com // 提取成单独的文件 MiniCssExtractPlugin.loader, "css-loader" ], exclude: /node_modules/, }, ] }, plugins: [ new MiniCssExtractPlugin({ // 定义输出文件名和目录 filename: "asset/css/main.css", }) ], optimization: { minimize: true, minimizer: [ // 压缩 css new CssMinimizerPlugin({}), ], }, }压缩 html
module.export = { plugins: [ new HtmlWebpackPlugin({ // 动态生成 html 文件 template: "./index.html", minify: { // 压缩HTML removeComments: true, // 移除HTML中的注释 collapseWhitespace: true, // 删除空⽩符与换⾏符 minifyCSS: true // 压缩内联css }, }) ] }压缩图片
module.exports = { module: { rules: [ { test: /.(png|jpg|gif|jpeg|webp|svg)$/, use: [ "file-loader", { loader: "image-webpack-loader", options: { mozjpeg: { progressive: true, }, optipng: { enabled: false, }, pngquant: { quality: [0.65, 0.9], speed: 4, }, gifsicle: { interlaced: false, }, }, }, ], exclude: /node_modules/, //排除 node_modules 目录 }, ] }, }按需加载
const List = lazyComponent('list', () => import(/* webpackChunkName: "list" */ '@/pages/list')); const Edit = lazyComponent('edit', () => import(/* webpackChunkName: "list" */ '@/pages/edit'));但需要注意一点:动态导入 import() 一个模块,这个模块就不能再出现被其他模块使用 同步 import 方式导入。比如,一个路由模块在注册 <Route /> 时采用动态 import() 导入,但在这个模块对外暴露了一些变量方法供其他子模块使用,在这些子模块中使用了同步 ESModule import 方式引入,这就造成了 动态 import() 的失效。
document.getElementById('btn1').onclick = function() { import( /* webpackChunkName: "btnChunk" */ /* webpackPrefetch: true*/ './module1.js' ).then(fn => fn.default()); }这行代码表示在浏览器空闲时加载 module1.js 模块,并且单独拆一个 chunk,叫做 btnChunk
module.exports = { //... optimization: { splitChunks: { chunks: 'async', // 值有 `all`,`async` 和 `initial` minSize: 20000, // 生成 chunk 的最小体积(以 bytes 为单位)。 minRemainingSize: 0, minChunks: 1, // 拆分前必须共享模块的最小 chunks 数。 maxAsyncRequests: 30, // 按需加载时的最大并行请求数。 maxInitialRequests: 30, // 入口点的最大并行请求数。 enforceSizeThreshold: 50000, cacheGroups: { defaultVendors: { test: /[/]node_modules[/]/, //第三方模块拆出来 priority: -10, reuseExistingChunk: true, }, util.vendors: { test: /[/]utils[/]/, //公共模块拆出来 minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, }, };tree shaking
4.只能处理 JS 相关冗余代码,不能处理 CSS 冗余代码。
const path = require("path"); const PurgecssPlugin = require("purgecss-webpack-plugin"); const glob = require("glob"); // 文件匹配模式 module.exports = { //... plugins: [ ... new PurgeCSSPlugin({ paths: glob.sync(`${PATH.src}/**/*`, { nodir: true }), }) // Add your plugins here // Learn more about plugins from https://webpack.js.org/configuration/plugins/ ], };gzip
前端除了在打包的时候将无用的代码或者 console、注释剔除之外。我们还可以使用 Gzip 对资源进行进一步压缩。那么浏览器和服务端是如何通信来支持 Gzip 呢?当用户访问 web 站点的时候,会在 request header 中设置 accept-encoding:gzip,表明浏览器是否支持 Gzip。服务器在收到请求后,判断如果需要返回 Gzip 压缩后的文件那么服务器就会先将我们的 JS\CSS 等其他资源文件进行 Gzip 压缩后再传输到客户端,同时将 response headers 设置 content-encoding:gzip。反之,则返回源文件。
const CompressionWebpackPlugin = require("compression-webpack-plugin"); // 需要安装 module.exports = { plugins: [ new CompressionWebpackPlugin() ] }作用域提升
module.exports = { //方式1 mode: 'production', //方式2 plugins: [ // 开启 Scope Hoisting 功能 new webpack.optimize.ModuleConcatenationPlugin() ] }