六个核心要素 入口(Entry), 出口(Output),模块(Module),代码块(Chunk),模块转化器(Loader),扩展(Plugin)

1.入口(Entry)

入口(entry),这是Webpack执行构建的第一步,可理解为输入。
入口可以有单入口和多入口。

  1. 单入口:
  2. const { resolve } = require('path' );
  3. module.exports =
  4. {
  5. entry:'./src/index.js',
  6. output:
  7. {
  8. filename:'bulid.js',
  9. path: resolve(__dirname, 'build'),
  10. }
  11. }
  12. 多入口:有几个入口文件就会打包生成几个chunk 并输入几个bundle, chunk 的名称是key
  13. const { resolve } = require('path' );
  14. module.exports =
  15. {
  16. entry:['./src/index.js', './src/main.js'],
  17. output:
  18. {
  19. filename:'bulid.js',
  20. path: resolve(__dirname, 'build'),
  21. }
  22. }
  23. 也可采用对象配置多入口文件
  24. const { resolve } = require('path' );
  25. module.exports =
  26. {
  27. entry:
  28. {
  29. one: './src/index.js',
  30. two: './src/main.js',
  31. },
  32. output:{
  33. filename:'[name].js',
  34. path: resolve(__dirname, 'build'),}
  35. }
  36. 还可以采用混合格式的多入口文件
  37. const { resolve } = require('path' );
  38. module.exports =
  39. {
  40. entry:
  41. {
  42. onea: ['./src/index.js', './src/main.js'],
  43. twob: './src/main.js',
  44. },
  45. output:{
  46. filename:'[name].js',
  47. path: resolve(__dirname, 'build'),}
  48. }

2.出口(Output)

  1. 出口输出结果,源码在Webpack中经过一系列处理后而得出的最终结果,可指定输入位置,输出结果的文件夹名称和文件名称

3.模块转化器(Loader)

3.1 css:

先把各种loader npm/yarn 下来
编译css 用css-loader style-loader, postcss-loader。
开发环境用style-loader 生产环境MiniCssExtractPlugin.loader。
postcss-loader 可用来给css 添加兼容 。
新建postcss.config.js npm -i autoprefixer -S。

const NODE_ENV = process.env.NODE_ENV;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          NODE_ENV === 'development'? 'style-loader': {
            loader: MiniCssExtractPlugin.loader,
          },
          'css-loader',
          'postcss-loader',
        ],
      },
      {
        test: /\.less$/,
        use: [
          NODE_ENV === 'development'? 'style-loader': {
            loader: MiniCssExtractPlugin.loader,
          },
          'css-loader',
          'less-loader',
          'postcss-loader',
        ],
      },
    ],
  }

3.1 js:

跟CSS一样,先安装bable- loader

4.插件(Plugin)

Plugin ,loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
常用插件:
htmlWebpackPlugin 插件文档https://github.com/jantimon/html-webpack-plugin#options
基本配置项

    pulgin:[
       new htmlWebpackPlugin({
           minify: {
               collapseWhitespace: true, // 移除空格
               removeComments: true, // 移除注释
           },
       }),
    ]

MiniCssExtractPlugin 插件文档 https://github.com/webpack-contrib/mini-css-extract-plugin

    new MiniCssExtractPlugin({
      filename: 'css/bundle_[chunkhash:8].css',
    }),

此插件可以解决把服务端渲染css 样式会闪的情况

extract-text-webpack-plugin把css 提取到单一文件中
TerserPlugin 插件文档 https://webpack.docschina.org/plugins/terser-webpack-plugin/

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        test: /\.js(\?.*)?$/i, //匹配参与压缩的文件
        parallel: true, //使用多进程并发运行
        terserOptions: {
          //Terser 压缩配置
          output: { comments: false },
        },
        extractComments: true, //将注释剥离到单独的文件中
      }),
    ],
  },

预加载插件
preload-webpack-plugin

5.其他

懒加载和预加载
动态加载是对于某个chunk 需要的时候在加载
预加载是浏览器空闲的时候在偷偷加载
同步加载是并行同时加载
动态加载 使用 import() webpack 的魔术字符串
预加载使用的是 preload-webpack-plugin 插件
bundle, module, chunk 的区别
image.png
总结来说 三者是同一个东西,我们写的是module ,在webpack 里处理的是 chunk 最后生成给浏览器的是 bundle

webpack热更新原理

  1. 本地启动一个本地服务。
  2. 改变entry新增了两份文件 一个为sockio准备的,一个是监听webpack 更新逻辑的。
  3. 监听webpack 编译结束,给浏览器发送hash 值,可以让浏览器知道怎么更新。
  4. 监听webpack文件编译文件变化,这块用的是webpack-dev-middleware这个库,这个可是把编译后的文件存在了内存里,所以在开发模式,dist 文件夹下没有文件,因为从内存中读取速度更快。
  5. 然后就是浏览器接收到热更新的通知开始检查下是否需要热更新,这个里就是第二部时候增加了两个入口文件,其中一个就是监听wepack 的更新逻辑的,
  6. moudle.hot.check 这个方法开始检查更新,然后会发送两个请求
  7. hotApply 热更新模块替换
  • 第一步,在webpack的watch模式下,webpack会监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码保存在内存中
  • 第二步是webpack-dev-serverwebpack之间的接口交互,dev-server的中间件middleware调用webpack暴露的API对代码变化进行监控,并且告诉webpack,将代码打包到内存中
  • 第三步是webpack-dev-server对文件变化的一个监控,变化后会通知浏览器端对应用进行live reload
  • 第四步也是webpack-dev-server代码的工作,该步骤主要是通过sockjs在浏览器端和服务端之间建立一个websocket长连接,将webpack编译打包的状态告知浏览器端,服务端传递的最主要信息是新模块的hash值,后面会根据hash值来进行模块热替换
  • webpack-dev-server并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又交回给了webpack,webpack的工作就是根据客户端传给它的信息以及dev-server的配置决定是刷新浏览器呢还是进行模块热更新。如果仅仅是刷新浏览器,就没有后面的步骤了
  • HMR.runtime是客户端HMR的中枢,它接收到传递给他的新模块的hash值,向服务端发送Ajax请求,服务端返回一个json,该json就是更新列表,再次通过请求,获取到最新的模块代码
  • HotModulePlugin将会对新旧模块进行对比,决定是否更新模块,如果要更新,检查模块之间的依赖关系,更新模块的同时更新依赖
  • 最后,当HMR失败后,回退到live reload操作,也就是进行浏览器刷新来获取最新打包代码

webpack 中 chunkHash 与 contentHash 区别:

chunkHash 是根据不同的入口文件进行生成的,如果我们在生产环境把公共库和程序文件分开,这样的话如果只是修改程序文件的话 公共库的是不变的,但是这样会有一个问题就是生成的js 和css 文件的hash 是一致的也就是说如果技术文件改了,但是css 文件没有改的话,css 文件的hash 也会改变。
contentHash 是基于文件内容的,css 和js 文件是分离的,这样的话改变js 文件 css文件是不会变的。
hash ,是全项目统一进行修改,修改一个文件整个文件的hash 都会变

webpack treeshaking

是把用到得方法打到bunder 里,不用的会在 uglify 阶段给移除掉,这样就优化的项目体积,在webpack 4, 5 版本中会默认开始,但是只能优化es6 import 的代码,不能使用commjs 语法, 所以在项目中如果使用了把es6 语法转化了tree 就会无效,还有就是treeshaking 对有副作用的方法无效, 有副作用的方法是会影响外部的变量或者相同的输入但是输出是不一样的, 如果是引用的外部全局变量或者影响了外部变量,那这个方法就是有副作用的。