Webpack4.0 学习笔记(上)

date
Mar 3, 2020
slug
webpack4.x-note-1
status
Published
tags
Webpack
summary
webpack深入学习笔记,内含常见配置案例
type
Post

webpack是什么?

webpack 是模块打包工具,底层的文件处理逻辑全部由 node 完成

支持的模块的规范

webpack 支持多种模块规范,es6: import/export default | common.js: reuqire/moudle.export | AMD: define/require | styles file: @import | resource file: <img src=...>。在 webpack 发展初期只是打包 js,但随着发展后现在可以打包 js/css 等文章

loader

loader 就是 webpack 除 js 文件外帮助其识别、处理对应资源的 js 文件

  1. file-loader 就是将图片资源复制粘贴进你配置的打包文件路径中,并将最新的符合你配置规则的图片名称(路径)返回,供代码使用
  1. ['style-loader', 'css-loader'] 先执行 css-loader 分析清楚 css 间的关系,并将其整合为一个 css 文件;style-loader 则将这个 css 文件挂载到 html 的 head 底部。
  1. css-loader 的 options 中设置 importLoaders: 2 指的是 index.scss 中 @import 了 a.scss,a.scss 中 @import 了 b.scss,如果不加这一项就会导致 b.scss 无法走 scss-loader 设置这个的目的就是为了确保 b.scss 先走 postcss-loader =》scss-loader 再走 css-loader =》style-loader
  1. css moudle 的配置需要在 css-loader 的 option 中设置 modules: true 即可使用 style.xxx

plugin

plugin 是 webpack 的插件接口,这个插件接口使 webpack 变得极其灵活。原理就是可以在 webpack 运行到某一时刻的时候,帮你做一些事情。(类比生命周期的钩子函数)

  1. html-webpack-plugin: 该插件将为你生成一个 HTML5 文件, 并将打包生成的 js 自动插入到这个 html 中。当 webpack 打包资源结束这个时刻开始工作
  1. clean-webpack-plugin: 该插件当 webpack 打包前这个时刻先删除之前的打包文件(dist)
  1. webpack.HotMoudleReplacementPlugin() HMR 指的是在不刷新 .html 文件下只更新(保留当前页面的状态包括js结果)变动的代码(样式等)对应的在 devserver 中需要开启 hot/hotOnly

devServer

devServer 是 webpack 在本地的开发环境下利用 http-proxy-middleware & node 开启的一个服务器

这里主要说一下 proxy 的配置,如下:
module.exports = {
    // ...
    devServer: {
        contentBase: './dist',
        open: true,
        port: 8080,
        hot: true,
        hotOnly: true,
        proxy: {
            '/api': {
                target: 'https://www.xxx.com',
                secure: false,
                pathRewrite: {
                    'info.json': 'demo.json'
                },
                changeOrigin: true,
                headers: {
                    cookie: 'xxx'
                }
            }
        }
    }
}
  1. target 指接口转发的目标地址,如果目标使用了 https 协议,那么必须带上 secure: false,如果是 http,则可以不配置 secure 或者使其为 true
  1. pathRewrite 常用应用场景是后台正在开发接口,但是你这边需要数据,后端给了一个 mock 数据的接口,但是在业务代码中你又不想修改 info.json 为 demo.json,所以在这里进行配置后期注释掉即可
  1. changeOrigin 是修改发起请求的头信息,主要是为了防止转发的目标地址会对头信息做限制,导致拿不到数据
  1. headers 中设置一些头信息、cookie 主要用来模拟登陆状态

webpack 执行方式

  1. 命令行执行:https://webpack.docschina.org/api/cli/
  1. node 中执行:https://webpack.docschina.org/api/node/

提示

  1. npx 想要解决的主要问题,就是调用项目内部安装的模块
  1. npx create-react-app my-react-app 避免全局安装模块
  1. url-loader 中包含 file-loader 这俩者都能处理资源(图片、字体等)但是 url-loader 的好处就是可以转换将图片自动转为 base64
  1. output 中配置 cdn/oss 地址需要配置 publicPath 可以使用相关的 plugin 进行上传
  1. sourcemap 是一个映射 src 到 dist 中代码的映射关系
  1. 需要注意的点是 babel:
    1. // 该方案只针对于业务代码
      
      // npm install --save-dev babel-loader @babel/core
      
      {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
              presets: ['@babel/preset-env']
          }    
      }
      
      // 正常情况下我们是这样配置 babel 的,但如果在代码中使用了低版本浏览器不兼容的 promise、map 等方法该怎么办?
      
      // npm install --save @babel/polyfill
      
      {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
              presets: [['@babel/preset-env', {
                  targets: {
                      chrome: '67'
                  },
                  useBuiltIns: 'usage'
              }]]
          }    
      }
      
      // 这样配置后只需要在使用 es6 语法的地方 import "@babel/polyfill" 即可,但这
      // 样的问题是原本可能只有10多k大小的文件引入polyfill后变成上百k,但其实代码里只用
      // 到了 promise,这个时候就需要配置 useBuiltIns: 'usage' 这样就只会引入 
      // promise 相关的 polyfill,targets 的作用是当浏览器小于某个版本时才进行 
      // babel 的转换
      
      // webpack4 中不用在文件中 import "@babel/polyfill" 配置 useBuiltIns: 'usage' 后 babel 自动加上 polyfill
      // 该方案只针对于与业务无关的插件、类库等三方代码
      // 为什么这样做?因为 polyfill 会将方法注入至全局,污染全局环境
      
      // npm install --save-dev babel-loader @babel/core
      // npm install --save-dev @babel/plugin-transform-runtime
      // npm install --save @babel/runtime-corejs
      
      {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
             plugins: [['@babel/plugin-transform-runtime', {
                 corejs: 2,
                 helper: true,
                 regenerator: true,
                 useESModules: false
             }]]
          }    
      }
      
      // 去掉代码中的 import "@babel/polyfill" 然后执行即可
      // 如果 options 中配置参数较多可以将 options 对象直接提出放至项目根目录的 .babelrc 中即可
  1. 所有 loader 或者 loader 中的 options 配置执行顺序都是从下往上、从右往左
  1. 开启了 hotOnly: true 后局部更新后页面不会自动刷新
  1. 开启 devserver 后打包文件存在于内存中,想查看的话可以通 `npx webpack --config webpack.dev.config` 来避开 `webpack-dev-server --config webpack.dev.config`
  1. 前端spa路由需要注意的一个点是要配置 `historyApiFallback: true` 这样才能保证在地址栏输入路径后不被 devServer 的代理当作接口转发走
  1. resolve 的配置:
    1. module.exports = {
          // ...
          resolve: {
              // 配置 extensions 可以免去写文件后缀名,但是尽量不要也将资源类文件的后缀配进来(因为每次查找文件会使用node的fs模块,性能会受影响)
              extensions: ['.js', '.jsx'],
              // 配置 mainFiles 可以在引入时只写目录 eg: `import Child from './src/child'`,这样 webpack 会先找 child 目录下的 indexjs 没有的话会找 childjs
              mainFiles: ['index', 'child'],
              // 配置 alias 就可以使用别名
              alias: {
                  i7eo: path.resolve(__dirname, './src/child')
              }
          }
      }

© i7eo 2017 - 2022