webpack优化环境配置 -- 进阶篇知识要点汇总

本文汇总了webpack的高级优化技术,包括HMR热更新、source-map配置、oneOf加速打包、缓存策略、tree shaking减少代码体积、代码分割、懒加载与预加载、PWA、多进程打包、externals忽略打包、以及DLL提升构建效率。详细阐述了各项配置的使用场景和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、HMR

  • css样式只需要在devServer 里面 hot 配置为true即可
  • js文件需要在js文件里面加配置才可以实现,要不然是整个页面刷新
    注意: 只适用于非入口文件js
if (module.hot) {
  // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效
  module.hot.accept('./print.js', function() {
    // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
    // 会执行后面的回调函数
    doSomething();
  });
}

  • html文件不需要,若特殊场景需要的话,可以写到entry的配置里面去,如下:
entry: ['./src/js/index.js', './src/index.html']

2、source-map

一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
开发环境:速度快,调试更友好。

开发环境:速度快,调试更友好
速度快(eval>inline>cheap>…)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map

开发模式推荐配置:
eval-source-map / eval-cheap-module-souce-map

生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息

生产环境推荐配置:
source-map / cheap-module-souce-map

3、oneOf

rules里面的多个loader可以用oneOf包起来,这样可以使文件只被其中一个loader匹配处理,提升打包的速度和效率。个别需要多个loader处理的,可以放到oneOf外面,并指定 ** enforce: ‘pre’(优先执行) ** 来达到效果。

module: {
    rules: [
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 优先执行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        // 以下loader只会匹配一个
        // 注意:不能有两个配置处理同一种类型文件
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          /*
            正常来讲,一个文件只能被一个loader处理。
            当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
              先执行eslint 在执行babel
          */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: {version: 3},
                    targets: {
                      chrome: '60',
                      firefox: '50'
                    }
                  }
                ]
              ]
            }
          },
          {
            test: /\.(jpg|png|gif)/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              outputPath: 'imgs',
              esModule: false
            }
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              outputPath: 'media'
            }
          }
        ]
      }
    ]
  }

4、缓存

常用的缓存方式有

  • babel缓存:通过配置cacheDirectory参数,提升编译速度,缓存文件,再次修改后,只编译修改的文件。

{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'babel-loader',
  options: {
    presets: [
      [
        '@babel/preset-env',
        {
          useBuiltIns: 'usage',
          corejs: { version: 3 },
          targets: {
            chrome: '60',
            firefox: '50'
          }
        }
      ]
    ],
    // 开启babel缓存
    // 第二次构建时,会读取之前的缓存
    cacheDirectory: true
  }
}

  • 文件资源使用hash值来缓存
说明
hash每次wepack构建时会生成一个唯一的hash值,js和css同时使用一个hash值
chunkhash根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样。js和css同时使用一个hash值
contenthash根据文件的内容生成hash值。不同文件hash值一定不一样

推荐使用 contenthash

output: {
  filename: 'js/built.[contenthash:10].js',
  path: resolve(__dirname, 'build')
}

5、tree shaking

前提:

  1. 必须使用ES6模块化
  2. 开启production环境
process.env.NODE_ENV = 'production';
  1. 搭配压缩插件使用,比如 terser-webpack-plugin (可以同时压缩js和css)
    详细使用方法参见webpack配置详解【六】 – optimization详解

作用: 减少代码体积

避免误删一些文件,可以在package.json配置sideEffects

"sideEffects": ["*.css", "*.less",    "./src/js/xxx.js"]

这样css 和 lese致远就不会被删减。
也可以直接配置某个js不进行tree shaking。

6、代码分割

  • 多入口
  entry: {
    // 多入口:有一个入口,最终输出就有一个bundle
    index: './src/js/index.js',
    test: './src/js/test.js'
  }
  • optimization 提取公共文件为单独的trunk
  /*
    1. 可以将node_modules中代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
  • js代码的方式,让webpack打包成单独的trunk
/*
  通过js代码,让某个文件被单独打包成一个chunk
  import动态导入语法:能将某个文件单独打包
*/
import(/* webpackChunkName: 'test' */'./test')
  .then(({ mul, count }) => {
    // 文件加载成功~
    // eslint-disable-next-line
    console.log(mul(2, 5));
  })
  .catch(() => {
    // eslint-disable-next-line
    console.log('文件加载失败~');
  });

7、懒加载和预加载

在异步方法里面使用import来实现懒加载,比如在onclick事件里面使用import

加载方式说明特点
懒加载当文件需要使用时才加载,比如点击事件触发的时候只适合小文件,大文件会有等待时间,体验不好
预加载会在使用之前,提前加载js文件。(等其他资源加载完毕,浏览器空闲了,再偷偷加载资源)最优方案,但是有兼容问题
  • 懒加载:当文件需要使用时才加载,比如点击事件触发的时候(不适应大问题)
  • 预加载 prefetch:会在使用之前,提前加载js文件。(等其他资源加载完毕,浏览器空闲了,再偷偷加载资源)
document.getElementById('btn').onclick = function() {
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
    console.log(mul(4, 5));
  });
};

webpackChunkName可以指定输出的文件名,配置webpackPrefetch可以实现预加载。

8、PWA技术

在网络离线的时候,可以使用已经缓存过的资源。
部分浏览器支持,适配的时候需要判断浏览器是否支持。
此项技术依赖插件 workbox-webpack-plugin,使用前需要先安装

npm i -D workbox-webpack-plugin

在webpack.config.js中配置

//先引入
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

//然后再plugins里面配置
plugins:[
	new WorkboxWebpackPlugin.GenerateSW({
	  /*
	    1. 帮助serviceworker快速启动
	    2. 删除旧的 serviceworker
	
	    生成一个 serviceworker 配置文件~
	  */
	  clientsClaim: true,
	  skipWaiting: true
	})
]

然后在入口js文件中注册serviceWorker

// 注册serviceWorker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/js/service-worker.js')
      .then(() => {
        console.log('sw注册成功了~');
      })
      .catch(() => {
        console.log('sw注册失败了~');
      });
  });
}

这样在第一次访问后,会缓存到serviceWorker里面,下次访问的时候优先会从缓存里面取,就算没网也没关系。

9、多进程打包

利用thread-loader来实现,一般用来打包js。
进程启动、进程通信都有开销, 只使用打包时间需要很长的,才适用 ,要不然得不偿失,反而耗时更久。

npm i -D thread-loader


{
	loader: 'thread-loader',
	options: {
	  workers: 2 // 可以指定进程的个数
	}
}

10、externals

忽略不想打的包,比如jquery我们只想cdn引入

webpack.config.js添加

externals: {
	// 忽略库名 --npm包名
	jquery: 'jQuery'
}

当我们忽略库的时候,一定要记得在html里面手动引入对应的库。

11、DLL

可以定义一个单独的webpack配置文件,里面专门打包这些不会经常变的库文件。
这样在需要的时候打包一次之后,其余业务代码变动的时候,不再对这些资源进行构建,这样来提升开发时候的构建效率。

  • 步骤1:

比如我们新起一个配置文件叫webpack.dll.js

/*
  使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
    当库的内容变化的时候,直接运行 webpack.dll.js 文件打包一次即可
    webpack --config webpack.dll.js
*/

const { resolve } = require('path');
const webpack = require("webpack");

module.exports = {
    entry:{
        jquery:['jquery']
    },
    output:{
        filename:'[name].dll.js',
        path:resolve(__dirname,'dist/dll'),
        library:'[name]_[hash:10]'
    },
    plugins:[
        new webpack.DllPlugin({
            name:'[name]_[hash:10]',
            path:resolve(__dirname,'dist/dll/[name].manifest.json')
        })
    ],
    mode: 'production'
}

第一次我们执行下打包即可

webpack --config webpack.dll.js

后续若有改动再次执行上述打包命令即可,无修改可不管。

  • 步骤2:
    先安装依赖插件add-asset-html-webpack-plugin
    然后在webpack的默认配置文件webpack.config.js中增加内容
const webpack = require("webpack");
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');


plugins:[
	//告诉webpack哪些库不参与打包
    new webpack.DllReferencePlugin({
      manifest:resolve(__dirname,"dist/dll/jquery.manifest.json")
    }),
    //把manifest.json里面的文件打包出去,并在html中自动引入该资源
    new AddAssetHtmlWebpackPlugin({
      filepath:resolve(__dirname,'dist/dll/jquery.dll.js')
    })
]

这样不会经常变动的库,我们通过webpack --config webpack.dll.js来打包,平常我们执行webpack就会更快一点。

如果打包多个库,参考代码:

  • webpack.dll.js中配置多个入口文件
entry: {
	jquery: ['jquery'],
	react: ['react', 'react-dom']
},

  • 相应的,webpack.config.js中也需配置多个new AddAssetHtmlWebpackPlugin和new DllReferencePlugin插件
new AddAssetHtmlWebpackPlugin({
	filepath: path.resolve(__dirname, 'dist/dll/jquery.dll.js')  
}),
new AddAssetHtmlWebpackPlugin({
	filepath: path.resolve(__dirname, 'dist/dll/react.dll.js')
}),
new webpack.DllReferencePlugin({
	manifest: path.resolve(__dirname, 'dist/dll/jquery.manifest.json')
}),
new webpack.DllReferencePlugin({
	manifest: path.resolve(__dirname, 'dist/dll/react.manifest.json')
}),
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值