webpack 快速上手

67 阅读5分钟

webpack (模块打包,代买拆分,资源载入)

  • 快速上手

  • webpack4以后新增工作模式

    • webpack.config.js 配置文件中增加 mode: "production development none"

    • 命令行增加

      ​
      webpack --mode production  //默认
      webpack --mode development
      webpack --mode none  //最原始状态的打包
      

2.资源模块加载 webpack.docschina.org/loaders

  • loader

    • file-loader
    • {       test: /.png$/,
             // use: ['file-loader']
             use: ['url-loader'],
             options: {
               limit: 10 * 1024
         } // url-loader 文件超出会调用file-loader
      

3.url加载(Data Urls)

  • url-loader
  • 最佳实践,对项目中小的文件实行Data Urls打包,减少请求次数;大文件单独提取存放,提高加载速度

加载器分类 --loader执行顺序从数组后面往前面执行

  • 编译转换类型
  • 文件操作类型
  • 代码检查

webpack 处理ES2015

  • 安装babel-loader

    yarn add bable-loader @babel/core @babel/preset-env --dev
    
  • 配置

     {
            test: /.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset']
              }
            }
          }
    

模块加载

  • Es Modules === import

  • commonJs === require

  • Amd标准 === define require

  • html模块加载 webpack会将html文件作为字符串引入

    import footerHtml from './footer.html'document.write(footerHtml)
    
  • html-loader

  • 名称类型默认值描述
    sources`{BooleanObject}`true启用/禁用 sources 处理
    preprocessor{Function}undefined允许在处理前对内容进行预处理
    minimize`{BooleanObject}`在生产模式下为 true,其他情况为 false通知 html-loader 压缩 HTML
    esModule{Boolean}true启用/禁用 ES modules 语法

    esModule 配置

    • 这个配置项的作用,是指定引入文件的方式,是否指定es module的形式引入(也就是 improt name from ‘url’)这个配置项默认值是true,如果是true的情况下,那再使用require或者****引用方式就会出现上面的问题。

      解决方法:把esModule这个配置项配置为false, 或者在js中使用improt语法引入import src from '../cover.jpg'。 但是即使在js中使用了import语法还是解决不了在html中的引用问题。所以可以选择直接把esModule配置为false即可。

  • {
            test: /.html$/,
            use: {
              loader: 'html-loader',
              options: {
                esModule: false,
                sources: {
                  list: [
                    '...',
                    {
                      tag: 'img',
                      attribute: 'data-src',
                      type: 'src'
                    },
                    {
                      tag: 'a',
                      attribute: 'href',
                      type: 'src'
                    }
                  ]
                }
              }
            }
          }
    

webpack核心工作原理

!(C:\Users\15815\AppData\Roaming\Typora\typora-user-images\image-20211124213209697.png)

开发一个loader

  • webpack中loader要求返回的是javascript代码

插件-plugin

  • clear-webpack-plugin

      plugins: [new CleanWebpackPlugin()]
    
  • 自动生成 html文件- html-webpack-plugin

    • 同时输出多个页面文件,指定模板,添加标题,元信息
    module.exports = {
      mode: 'none',
      entry: './src/index.js',
      output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'output')
        // publicPath: 'output/' // htmlwebpackplugin会自动生成路径
      },
      module: {
        rules: [
          {
            test: /.md$/,
            use: ['html-loader', './markdown-loader.js']
          }
        ]
      },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: 'html-webpack-plugin',
          meta: {
            viewport: 'width=device-width'
          },
          template: './src/index.html'
        }),
        new HtmlWebpackPlugin({  // 可通过多个实例生成多个html文件
          filename: 'about.html'
        })
      ]
    }
    

插件总结-相比loader plugin拥有更宽泛的能力范围

  • 通过钩子机制实现

    webpack要求plugin输出一个函数或者包含apply方法的对象
    class MyPlugin {
      apply(compiler) {
        console.log('MyPlugin start')
        compiler.hooks.emit.tap('MyPlugin', (compilation) => {
          // compilation => 打包的上下文
          for (const name in compilation.assets) {
            if (name.endsWith('.js')) {
              const contents = compilation.assets[name].source()
              console.log(contents)
              const withoutComment = contents.replace(//*+*//g, '')
              compilation.assets[name] = {
                source: () => withoutComment,
                size: withoutComment.length //  要求包含size 和source方法
              }
            }
          }
        })
      }
    }
    

自动编译、自动刷新

//监听文件变化
//启动时添加参数 --watch
​
yarn webpack --watch//全局工具 browser-sync dist --files “**/*”

webpack-dev-server

//安装
yarn add webpack-dev-server 
//使用 可加参数 --open
yarn webpack-dev-server --open
    
 // 访问静态额外的资源文件\代理跨域  一般只在生产打包阶段使用// new CopyPlugin({
    //   patterns: [{ from: 'publice', to: 'dest' }]
    // }),
    devServer:{
          contentBase: './public', // 或者为 [],
    proxy: {
      '/api': {
         // localhost:8080/api/user => https://api.github.com/app/user
        target: 'https://api.github.com',
        pathRewrite: { // https://api.github.com/app/user =>  https://api.github.com/user 
          '^api': ''
        },
        changeOrigin: true  //改写主机名
      } 
    }       
}

souce-map 代码映射 源代码地图

  • 在代码末尾添加sourcemap文件引用

    ///# sourceMaoingURL=jquery-3.4.1.min.map
    
  • 配置sourcemap

      devtool: 'source-map'
    
  • webpack支持12不同的soucemap文件

  • sourcemap开发选择 ==== cheap-module-eval-sourcemap

  • sourcemap生产选择 ==== none

  • webpack.config.js输出可为对象或者数组,为数组是会打包输出多套代码

webpack自动刷新的问题-解决方案HMR(Hot Module Replacement)

  • 核心问题-自动刷新后页面状态丢失的问题

  • webpack开启HMR-webpack-dev-server中集成

    //使用webpack-dev-server 参数开启
     webpack-dev-serve --hot
    // 配置文件开启
     const webpack = require('webpack')
      devServer: {
        hot: true
      }
     new webpack.HotModuleReplacementPlugin()
    ​
     
    
  • HMR-api

  • 通过手动实现js热更新

    module.hot.accept('./edit.js', () => {
      console.log('module更新了')
    })
    ​
    
  • 图片模块热更新

    module.hot.accept('./better.png', () => {
      console.log('module更新了')
    })
    
  • HMR注意事项

    //每次代码更新后会导致之前的控制台信息刷屏
    //解决方案 hot-only
    // HMR相关代码会在打包阶段被移除
      devServer: {
       // hot: true
          hotOnly: true
      }
    

webpack生产环境优化-mode

webpack生产环境优化-mode

  1. 根据不同环境配置导出不同配置

  2. 一个环境对应一个配置文件

    1-..

    2-..

    一般由一个公共配置文件和两个不同环境文件组成

    • 由于Object.assign()会完全覆盖掉对象中同名的属性

      因此,采用webpack-merg npm模块

webpack DefinePlugin-为代码注入全局成员

  • DefinePlugin注入的默认为js代码
  • 注入值可通过 JSON.stringify()转换

Tree Shaking -- 移除未应用代码 生产模式中会自动引用

* optimization - 开启webpack内部优化配置
* useExports 标记未被引用代码
* minimize 压缩清除未被引用代码
* ![image-20211128215607529](C:\Users\15815\AppData\Roaming\Typora\typora-user-images\image-20211128215607529.png)

webpack合并模块 concatenateModules (也被成为scope Hoisting 作用域提升)

  • concatenateModule会尽可能的将所有模块合并输出到一个函数中

    optimization:{
     concatenateModules:true
    }
    
  • tree shaking作用的前提示使用EsModule

  • tree shaking 与 babel-loader -- babel-loader将代码转换为 commonjs会导致treeshaking失效

  • 配置babel-loader强制使用commonjs使treeshaking失效(modules:false 禁用commonjs转换)

webpack sideeffects新特性(副作用:模块除了导出成员之外还做了其他什么功能,一般开发npm模块时用到)

  • 生产环境会自动开启
  • package.json中可标明代码无副作用
  • sideeffects 注意 可表示有副作用的文件

webpack代码分割

  • 多入口打包

  • 动态导入

    1. 多入口打包

      entry:{
          index:  'index.js',
          album: 'album.js
      },
      output: {
          filename: '[name].bundle.js'
      }
      // 
      

      为页面指定js

      webpack-公共模块提取(将公共模块提取到一个文件夹中)

optimization:{
    splitchunks:{
        chunks: 'all'
    }
}

2.动态导入--实现按需加载

  • webpack会将动态导入的模块分包只有在使用时才加载

webpack 魔法注释

*  相同的chunkname会被打包在一起
*  ![image-20211128230649108](C:\Users\15815\AppData\Roaming\Typora\typora-user-images\image-20211128230649108.png)

MiniCssExtractPlugin-提取css到单个文件

  • style-loader(将样式通过style标签注入)=>

  • MiniCssExtractPlugin通过link注入样式文件,不再需要style.loader

  • 问题:webpack生产模式只压缩js文件,css文件需要手动处理

    通过使用插件 optimize-css-assets-webpack-plugin

  • webpack官方建议把压缩类插件配置到optimization中的minimize中

    optimization:{
        minimizer:[
        new OptimizeCssAssetsWebpackPlugin()
        ]
    }
    //需将js压缩手动添加回来
    optimization:{
        minimizer:[
        new TerserWebpackPlugin(),
        new OptimizeCssAssetsWebpackPlugin()
            ]
    }
    

    输出文件名 Hash

    • [hash]-项目级别 只要一文件改变其他文件名hash值全部改变
    • [chunkhash]-chunk级别 --不同的打包入口的文件的改变才会改变此入口文件名的hash值
    • contenthash-文件级别 --不同的文件有不同的hash值,文件改动只改变本文件的hash值
    • 指定文件hash值长度(默认16位): [chunkhash:8]