webpack原理/实践/理解

79 阅读3分钟

模块化只在开发阶段,webpack负责

  1. 编译(ES6->ES5,兼容),
  2. 打包(把一个个分散的模块打包到一个bundle.js文件,避免频繁请求模块)
  3. 同时支持不同类型的文件,png、css...

webpack打包的结果

生成一个立即执行函数

(function(modules){ 
  //....
  _require_函数,加载模块,执行
 })([fn1, fn2,...])

传入的参数是一个数组,其中的数组元素是一个个的函数,每个模块都会包裹在一个函数中,实现私有作用域

loader

webpack只能处理JS文件,loader帮忙加载处理其他类型的文件

  1. css-loader 负责打包,把css模块转成js,
  2. style-loader 使用css样式
  3. url-loader 不单独生成文件,直接生成一个Data URLs嵌入代码,url就可以表示内容 -- 适用体积较小的文件,

分类:

  • 编译转换 - css-loader
  • 文件操作 - file-loader 单独生成文件,bundle.js导出文件访问路径
  • 代码检查 - eslint-loader

webpack模块加载方式

  • ESModules import声明
  • CommonJS require函数
  • css样式代码中,@import,url函数
  • HTML代码中,< img src={}/>

实现一个loader

loader负责资源文件从输入到输出的转换,最后输出结果必须是JavaScript 对于同一个资源,可以依次使用多个loader 插件 html-webpack-plugin 清理dist

自动刷新问题 - HMR hotmoduleReplacement

  • 自动刷新 - 页面之前的操作会丢失
  • 模块热替换 - 运行过程中实时替换模块,应用运行状态不受影响
devServer:{
  hot: true
}
new webpack.HotModuleReplacementPlugin()
  • 样式文件热更新开箱即用? -- 经过loader处理,样式可以自动处理,直接替换就可以
  • JS文件没有规律,导出的可能是对象,函数,使用不确定
  • 框架下的开发,每个文件有规律,脚手架创建的项目内部都继承了HMR方案

Tree Shaking -

不是某个具体选项,功能搭配使用结果 生产模式下自动使用

optimization:{
   usedExport: true, //只导出被引用的
   minimize: true //代码压缩
}

scope hosting 合并模块

将所有模块合并输出到一个函数中

optimization:{
  concatenateModules: true
}

(webpack打包生成一个立即执行函数,参数数组元素,为每个模块对应的函数)

sideEffects

副作用:模块执行时,除了导出成员之外所做的事情

optimization:{
  sideEffects: true  //开启功能
}
------------package.json中
“sideEffects”:false  //标识代码没有副作用
"sideEffects":[文件路径1,...]

Code Spliting 代码分割

并不是每个模块在启动时必要,分包-按需加载

  1. 多入口打包,适用传统多页应用程序
entry: {
   index:'./scr/index.js',
   other:'./src/other.js'
}
output: {
   filename: '[name].bundle.js'
}
plugins:[
   new HtmlWebpackPlugin({
      title:'',
      chunks:''
   })
]
  1. 动态导入

webpack-dev-server

1.5

资源模块 - 加载其他类型模块

asset/resource 发送单独文件,并导出url asset/inline 带出资源url asset/source 导出资源源代码 asset 在导出data url和发送一个单独文件自动选择

module:{
   rules:[
      {
         test:/\.png$/,
         type:asset/...
      }
   ]
}

1.6 loader

引入,处理其他类型文件,供应用程序使用

  1. 加载css, style-loader,css-loader

  2. 抽离,压缩css,

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
    

1.7 babel-loader

webpack自带加载js模块的功能,但只能做模块化打包,不能转化js代码

{
   test: /\.js$/,
   exclude: /node_modules/, //排除这个下面的文件
   use: {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env']
     }
  }
}

1.8 代码分离

把代码分离到不同的bundle中,减小入口文件大小

  1. entry入口起点 多个入口文件,如果用了相同的模块,会被重复打包到各自bundle文件中

    // entry: './src/index.js', 
    entry: {
      index: './src/index.js',
      another: './src/another-module.js'
    }, //配置多入口 -- 相应的output内容也需修改
    output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, './dist'),
     clean: true, //清理dist
     assetModuleFilename: 'images/[contenthash][ext]'
    },
    
  2. 防止重复

    entry: {
      index: {
        import: './src/index.js',
        dependOn: 'shared'
      },
      another: {
        import: './src/another-module.js',
        dependOn: 'shared'
      },
      shared: 'lodash'
    }
    
  3. 动态导入

  • 懒加载/按需加载 使用时加载
  • 预获取/预加载 网络空闲时加载

1.9 缓存

  1. 缓存本地代码
  2. 缓存第三方库

1.10

命令脚本优化,npm run start/build即可

"scripts": { 
  "start": "npx webpack serve -c ./config/webpack.config.dev.js",
   "build": "webpack serve -c ./config/webpack.config.prod.js"
}

拆分配置文件 => config.dev prod.dev 提取公共配置,并合并

    const { merge } = require('webpack-merge');
    const commonConfig = require('./webpack.config.common');
    const productionConfig = require('./webpack.config.prod');
    const devConfig = require('./webpack.config.dev');
    module.exports = (env) => {
      switch (true) {
        case env.development:
            return merge(commonConfig, devConfig)
        case env.production:
            return merge(commonConfig, productionConfig)
        default:
            return new Error('no match config')
      }
    }