py-tofee / Notes

2 stars 0 forks source link

Webpack #10

Open py-tofee opened 3 years ago

py-tofee commented 3 years ago

plugins 插件

webpack-dev-middleware

wepack-hot-middleware

py-tofee commented 3 years ago

webpack 运行原理

  1. webpack函数在运行时,读取webpac.config.js配置文件,生成compiler实例,遍历plugin数组,把compiler实例注入到plugin的apply方法中(每个plugin必须要实现一个apply方法);这样,在apply方法中,就可以监听compiler的钩子函数,在特定的时候执行相关操作,优化输出的打包代码;
  2. 读取配置的entries,递归遍历所有入口文件;
  3. 对入口文件进行编译,开始compilation过程,使用loader对文件内容进行编译,再将编译好的文件内容解析成AST静态语法树;
  4. 递归依赖的模块,重复第3步,生成AST语法树,在语法树中可以分析到模块之间的依赖关系,对应做出优化(tree shaking);
  5. 将所有模块中的require(babel-loader将ES6的import转换成commonJS的require)语法替换成__webpack_require__(一个函数,传入模块名称,返回模块的引用)来模拟操作;
  6. 最后把所有的模块打包进一个自执行函数(IIFE)中。
py-tofee commented 3 years ago

webpack优化策略

性能优化篇---Webpack构建速度优化

  1. 构建速度优化
    • 可视化查看webpack构建分析,webpack-bundle-analyzer插件
      // 判断生产环境
      if (process.env.NODE_ENV === 'production') {  // npm run build 时
      if (process.env.npm_config_report) {
      config
      .plugin('webpack-bundle-analyzer')
      .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
      .end()
      }
      }

      在vue中,执行 npm run build --report时,在全局process.env中新增了一个属性 npm_config_report 为 true,所以会调用BundleAnalyzerPlugin;

py-tofee commented 3 years ago

使用DllPlugin优化

在webpack进行打包时,对于某些依赖的第三方库,如'vue', 'vue-router', 'vuex', 'axios', 'element-ui', 'lodash'等,不会修改和升级的库,可以让它和业务代码分开打包;

实现目标

py-tofee commented 3 years ago

压缩js文件

py-tofee commented 3 years ago

模块拆分

splitChunks:

py-tofee commented 3 years ago

webpack HMR 热更新原理

参考链接 HMR:Hot Module Replacement 优点:不刷新浏览器的前提下,更新页面,保存页面的状态,提升开发效率; 启动:"start": "webpack-dev-server --hot --open" sockjs:webpack-dev-server中的一个依赖库

  1. 通过npm start启动devServer服务,--hot配置告诉webpack自动引入HotModuleReplacementPlugin插件,而不需要手动引入;
  2. webpack-dev-middleware插件监听文件的变化,通知webpack重新执行编译打包;并将打包后的文件保存在内存中,而不是output.path目录下,原因:访问内存中的文件比访问文件系统中的文件更快,且减少了代码写入文件的开销;
  3. 在devServer启动的时候,通过sockjs在devServer和浏览器端建立一个webSocket长链接,webpack-dev-server监听compile是否完成,当compile完成后,通过这个webSocket长链接 将编译打包后的新模块的hash值告知浏览器端;
  4. 启动时,webpack-dev-server修改entry 入口文件,在里面加入了webpack-dev-client相关代码,用于接收webSocket消息;
  5. 浏览器接收到最新的hash值,通过jsonp向devServer请求最新的模块代码,并将新的模块代码返回给HMR runtime;
  6. HMR runtime 对新的模块代码做进一步处理,决定是直接刷新浏览器页面,还是进行后面的热更新操作;
  7. 如果需要执行热更新,HMR会对新旧模块代码进行对比,更新模块的同时,也更新模块之间的依赖关系,实现不刷新浏览器的前提下,更新页面;
  8. 如果热更新失败,那么将直接刷新浏览器,实现代码更新; image
py-tofee commented 3 years ago

开发中的一些配置

require-context

style-resources-loader

style-resources-loader 可以自动导入less等预处理器的公共样式变量,避免在每个样式文件中手动@import导入

pluginOptions: {
  'style-resources-loader': {
    preProcessor: 'less',
    patterns: [
      resolve('src/assets/variables.less'),
      resolve('src/assets/function.less')
    ]
  }
}

svg-sprite-loader

svg-sprite-loader可以将常用的多个svg图标,拼接成 雪碧图,当夜页面中使用svg-icon时,就不需要通过svg的URL导入了

src/icons目录下有多个svg图片
a.svg: <svg>{{省略的icon path}}</svg>
b.svg: <svg>{{省略的icon path}}</svg>
...
使用svg-sprite-loader之后,变成一个svg图片
<svg>
    <symbol class="icon" viewBox="0 0 1024 1024" id="a-icon">{{省略的icon path}}</symbol>
    <symbol class="icon" viewBox="0 0 1024 1024" id="b-icon">{{省略的icon path}}</symbol>
</svg>
定义一个全局vue组件<SvgIcon>,iconName指向symbolId,就可以复用对应symbol的图片啦
<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>

在src/icons目录下,新建一个index.js文件,使用require.context动态引入所有svg图片,

try {
  const req = require.context('./svg', false, /\.svg$/)
  const requireAll = requireContext => requireContext.keys().map(requireContext)
  requireAll(req)
} catch (e) {
  // ignore
  console.warn('load svg icons error.')
}

配置全局可用的常量和指向公共模块的变量

plugins: [
  new webpack.BannerPlugin(`bulid time: ${moment().format('YYYY-MM-DD HH:mm:ss')}`),
  // 配置全局常量,可以在代码中使用
  new webpack.DefinePlugin({
    'process.env.CFG': JSON.stringify(process.env.CFG),
    'modeFlag': JSON.stringify(process.env.modeFlag)
  }),
  // 自动加载配置的模块,在使用时不需要再导入
  new webpack.ProvidePlugin({
    _: 'lodash'
  })
]