1. webpack基础知识

首先以下讨论的操作均基于webpack 4.41.6 讨论,并且node版本在10以上。

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。 在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

2. webpack五个核心

2.1 entry

入口文件位置配置项,webpack会根据该文件开始打包

2.2 output

输出文件配置项,配置输出位置和定义打包文件名。

2.3 loader

webpack本身只能处理js/json格式的资源,其他资源的需要配置该项来进行打包

2.4 plugins

插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。

2.5 mode

用于配置生产环境(production)还是开发环境(development)。

3. webpack最基本的命令

首先我们需要初始化npm init 然后 下载安装 webpack webpack-cli webpack-dev-server

npm install webpack webpack-cli -g //全局安装
npm install webpack webpack-cli webpack-dev-server -D //局部安装到开发环境

在文件夹下创建src/index.js ,再创建一个build文件用于存放打包文件
当然最基础的的打包命令如下:

开发环境(代码不会压缩): webpack src/js/index.js -o build/js/built.js --mode=development

生产环境(代码会压缩):webpack src/js/index.js -o build/js/built.js --mode=production

但是通过上述的方式只能打包js/son文件。

4. webpack配置一个常用的开发模式打包设置

这里我们需要在与src同目录创建一个配置文件 webpackconfig.js ,以下我直接贴出完整代码,详细看注释

const { resolve } = require('path');//为了适配不同环境的绝对路径
const htmlWebpackPlugin = require('html-webpack-plugin');//打包html文件的插件模块

module.exports = {//webpack使用的模块化规范和node一样。基于coommonJS
  entry:'./src/index.js',//入口文件
  output: {//输出配置
    filename: 'js/built.js',//入口文件打包后的文件名和目录位置
    path: resolve(__dirname,'build/'+getNowFormatTime())//打包文件夹,存放生成的打包文件
  },
  module: {//处理非js/json的配置
    rules: [
      {
        //处理less资源
        test: /\.less$/,//正则识别less文件
        use:['style-loader', 'css-loader', 'less-loader']//打包需要的依赖loader,这里的执行顺序是从右往左从下往上,之一顺序不能乱
      },
      {
        //处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        //处理样式中的图片资源
        test: /\.(jpg|png|gif)$/,
        loader:'url-loader',//当需要的loader只有一个是可以用该方式代替use:[...]
        options: {
          limit: 8 * 1024,//当图片小于8k就会被转为base64格式,优点:减少请求次数,缺点:会使图片大小增大些
          name: '[hash:10].[ext]',//图片打包后是以hash方式命名的,这里设置是只取hash命名的前十位,并且后缀名不变
          outputPath:'img'//修改图片输出路径到img下
        }
      },
      {
        //处理html中的图片路径
        test: /\.html$/,
        loader:'html-loader',
      },
      {
        //处理其他资源
        exclude:/\.(html|css|js|less|jpg|png|gif)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath:'static'
        }
      }
    ]
  },
  plugins: [//插件的配置
    new htmlWebpackPlugin({//用以将html打包
      template: './src/index.html'//将源代码中的html格式复制到打包文件的html中
    })
  ],
  mode: 'development',//打包方式,development为开发模式,代码不压缩,production为生产模式代码要压缩
  devServer: {//配置自动化打包编译服务器
    contentBase: resolve(__dirname,'build'),//打包需要输出的目录
    compress: true,//是否启用gzip压缩
    port:3000,//端口号
    open:true//是否打开浏览器
  }
}

//注意xxx-load 需要事先通过 npm 进行下载

//这里是我为了每次打包输出的目录不一样而设置的用当前时间命名打包名
function getNowFormatDay(nowDate) {
  if(nowDate == null){
      nowDate = new Date();
  }
  var day = nowDate.getDate();
  var month = nowDate.getMonth() + 1;//注意月份需要+1
  var year = nowDate.getFullYear();
  //补全0,并拼接
  return "" + year  + completeDate(month) +completeDate(day);
}

function getNowFormatTime() {
  var nowDate = new Date();
  var h = nowDate.getHours();
  var m = nowDate.getMinutes();
  var s = nowDate.getSeconds();
  //补全0,并拼接
  return "" + getNowFormatDay(nowDate) + completeDate(h)+ completeDate(m) + completeDate(s);
}


//补全0
function completeDate(value) {
  return value < 10 ? "0"+value:value;
}

5. webpack单独提取css文件

在之前我们打包是把css文件和js文件一起打包在一个文件中,但这样在实际生产的时候会导致css加载过慢,所以我们要单独提取出来再通过link标签引入

注意以下webpack路径设置都依照以下目录进行输出

image-20210117233405502

依赖下载

npm i mini-css-extract-plugin -D

在之前我们通过style-loader对css进行打包,但是是将css打包到js中,所以我们现在不能使用这个loader,代码如下:

const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const miniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/build.js',
    path: resolve(__dirname,'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          //'style-loader',
          //使用miniCssExtractPlugin.loader取代style-loader就可以实现将css单独分离打包出来
          miniCssExtractPlugin.loader,
           'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './src/index.html'
    }),
    new miniCssExtractPlugin({
      //对单独输出的css目录进行修改
      filename:'css/built.css'
    })
  ],
  mode: 'development'
}

6. webpack对css做兼容处理/css的压缩

依赖下载

npm i postcss-loader postcss-preset-env optimize-css-assets-webpack-plugin -D

代码如下:

const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const miniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
//设置nodejs的环境变量
//process.env.NODE_ENV = 'development';

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/build.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          //'style-loader',
          //使用miniCssExtractPlugin.loader取代style-loader就可以实现将css单独分离打包出来
          miniCssExtractPlugin.loader,
          'css-loader',
          /* 
            css兼容处理  依赖 postcss 库--->  需下载下面两个依赖  postcss-loader postcss-preset-env
          */
          //第一种写法,使用loader的默认配置
          //'postcss-loader'  但是这种写法什么都没配置,只有默认的
          //第二种写法  修改loader的配置
          {
            loader: 'postcss-loader',//当然如果就单写这一句和上一句一样的作用
            options: {
              //注意这里写法可能会随着版本而变化,所以要时刻关注各个插件的写法变化
                //postcss的插件,下面这个插件主要用来读取package.json中的browserslist里面的配置,通过配置加载指定的css兼容性样式
                /* 
                  "browserslist": {
                    // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
                    "development": [
                      "last 1 chrome version",//兼容最近一个的谷歌版本
                      "last 1 firefox version",
                      "last 1 safari version"
                    ],
                    // 生产环境:默认是看生产环境(与本文件的mode设置无关)
                    "production": [
                      ">0.2%",//出了0.2%的浏览器版本其他都兼容
                      "not dead",//不兼容已经死掉的(ie10)浏览器
                      "not op_mini all"//不兼容所有欧朋浏览器
                    ]
                  } 
                  */
                 postcssOptions: {
                   plugins: [
                     ['postcss-preset-env',{}]
                   ]
                 }   
            }
          }

        ]
      }
    ]
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './src/index.html'
    }),
    new miniCssExtractPlugin({
      //对单独输出的css目录进行修改
      filename: 'css/built.css'
    }),
      //对css压缩只需引入这个对象即可
    new optimizeCssAssetsWebpackPlugin()  
  ],
  mode: 'development'
}

注意在webpack配置后还要再package.json中去配置browserslist

7. webpack js的语法检查

依赖下载

npm i eslint-loader  eslint eslint-config-airbnb-base  eslint-plugin-import -D

代码如下:

const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      /* 语法检查
         主要是规范代码的编写格式,统一代码格式,检查常见的语法错误 需下载 eslint-loader  eslint
         注意只检查自己写的代码,别检查其他库的源代码
         设置检查规则   在package.json中的eslintConfig中设置
         推荐使用airbnb代码规范 (github上去看看)  还要下载依赖eslint-config-airbnb-base  eslint-plugin-import 
         package.json中的eslintConfig为
         "eslintConfig": {
            "extends": "airbnb-base"
          }
      */
      {
        test: /\.js$/,
        exclude: /node_modules/,//排除node_modules中的代码检查
        loader: 'eslint-loader',
        options: {
          //代表自动修复语法规范
          fix:true
        }
      }
    ]
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
}

也是注意别忘了package.json中配置eslintConfig

8. webpack js的兼容处理

依赖下载

// js的兼容处理 依赖 babel-loader @babel/preset-env @babel/core  
// 要想对所有js写法进行兼容性处理则需要再引入 @babel/polyfill,下载后可以直接在入口js中通过import引入即可(这样会引入新的问题     就是打包后体积较大)
// 另一种解决方案:按需兼容性处理,需引入 core-js  ,注意使用该方案的话就要注释掉 @babel/polyfill
const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      /* js的兼容处理 依赖 babel-loader @babel/preset-env @babel/core */
      //要想对所有js写法进行兼容性处理则需要再引入 @babel/polyfill,下载后可以直接在入口js中通过import引入即可(这样会引入新的问题就是打包后体积变大)
      //另一种解决方案:按需兼容性处理  需引入 core-js  ,注意使用该方案的话就要注释掉 @babel/polyfill
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          //预设:指示babel做什么样的兼容性处理,如果只写下面这一行的预设,则只会对一些js语法进行兼容转换 所以还要下载 
          presets: [
            [
              '@babel/preset-env',
              {
                useBuiltIns: 'usage',
                //指定corejs的版本
                corejs: {
                  version: 3
                },
                //指定兼容性到哪个版本
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ]
        }
      }
    ]
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
}

9. webpack 压缩html

这个在之前的 html-webpack-plugin 插件中就可以配置

依赖下载

npm i html-webpack-plugin -D

代码如下:

const { resolve } = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {

  },
  plugins: [
    new htmlWebpackPlugin({
      template: './src/index.html',
      //压缩处理
      minify: {
        //移除空格
        collapseWhitespace: true,
        //移除注释
        removeComments: true
      }
    })
  ],
  mode: 'production'
}

10. webpack配置一个常用的生产模式打包设置

代码如下:

const { resolve } = require('path');
const miniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const htmlWebpackPlugin = require('html-webpack-plugin');
/* 注意当多个loader对同一种文件进行操作时,需要考虑清楚执行顺序
比如要先执行eslint-loader 再执行 babel-loader */

//设置nodejs的环境变量,决定browserlist兼容环境
process.env.NODE_ENV = 'production';

//css和less中对css的兼容处理是相同的所以把他提取出来减少重复代码
const commonCssLoader = [
  {
    loader:miniCssExtractPlugin.loader,
    options:{
        //这里主要解决css单独提取出来css中引入的图片的路径问题
      publicPath: '../'
    }
  },
  'css-loader',
  {
    loader: 'postcss-loader',
    options: {
      postcssOptions: {
        plugins: [
          ['postcss-preset-env', {}]
        ]
      }
    }
  }
]

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/build.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        //处理css
        test: /\.css$/,
        use: [...commonCssLoader],
      },
      {
        //处理less
        test: /\.less$/,
        use: [...commonCssLoader, 'less-loader'],
      },
      {
        //js的语法检查,注意要再package中配置检查风格
        test: /\.js$/,
        exclude: /node_modules/,
        enforce: 'pre',//表示优先执行eslint-loader
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        //js的兼容性处理
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                useBuiltIns: 'usage',
                //指定corejs的版本
                corejs: {
                  version: 3
                },
                //指定兼容性到哪个版本
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ]
        }
      },
      {
        //处理图片
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'img'
        }
      },
      {
        //处理html中的img
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        //其他文件处理
        exclude: /\.(html|css|js|json|less|jpg|png|gif)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'static'
        }
      }
    ]
  },
  plugins: [
    //将css单独提取
    new miniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    //压缩css
    new optimizeCssAssetsWebpackPlugin(),
    //处理html文件
    new htmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
}

11. webpack开发环境优化HMR

HMR,热模块替换,表示源文件中其中一个文件修改了,不会对所有文件进行打包,只对改动过的进行加载打包
开启方式,在devServer中配置hot为true就可以了,如下:

image-20210119002722170

但是之这样设置后对于样式文件是可以热模块加载的了,但是js文件默认是没有的HMR的功能的,需要在入口文件中写js代码配置监听
如要引入的index2.js文件如下:

console.log('我是index2`````````');
function test() {
  console.log('用了才会输出')
}

export default test;

index.js文件需要如下配置:

//引入
import './font/iconfont.css';
import './index.css';
import './index.less';
import a from './index2.js'

function add (x,y) {
  return x + y;
}

console.log(add(3,5));
//配置监听如下
if(module.hot) {
  module.hot.accept('./index2.js', function () {
    //方法会监听index2.js的变化,一旦发生变化就再次加载这个文件,其他文件不做变化
    //会执行后面的回调函数
    //所以可以将引入文件调用放入这里
    a();
  })
}

另外,html本身是没有热更新的,但是我们在源代码里修改了html,并不会对打包文件进行重新加载,所以我们这样修改html是没用的。
解决的方式:在entry中在添加html的路径就行了
image-20210119004602773

12. source-map

source-map: 一种 提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪源代码错误)。
配置方式webpack.config.js中与entry属性同级添加image-20210119004819634即可。

devtool还有其他的配置,根据不同情况进行选择:

source-map:打包后在外部生成map文件
错误代码准确信息 和 源代码的错误位置

inline-source-map:内联
只生成一个内联source-map
错误代码准确信息和源代码的错误位置

hidden-source-map:外部
错误代码错误原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码的错误位置

eval-source-map:内联
每一个文件都生成对应的source-map,都在eval
错误代码准确信息 和 源代码的错误位置

nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息

cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置 ,只能精确的行

cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置 module会将loader的source map加入

内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发环境:速度快,调试更友好

开发环境推荐使用eval-source-map

13. 缓存

babel缓存开启方式 cacheDirectory: true 让第二次打包速度更快
在babel-loader的options下添加即可
image-20210119005718163

文件资源缓存
一般我们是可以通过服务器请求的时候设置文件的强制缓存时间来实现缓存,但是会遇到一个问题就是,当我们突然要修改文件,但是还没到强制缓存的到期时间,这样就无法对文件进行及时的更新。我们可以通过修改文件名字的方式来对文件进行重新加载
方式一:hash 通过hash的方式命名文件 hash: 每次wepack构建时会生成一个唯一的hash值。问题:因为js和css同时使用一个hash值。如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)。

方式二: chunkhash 根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样问题: js和css的hash值还是一样的,因为css是在js中被引入的,所以同属于一个chunk。

方式三(推荐使用):contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样 ,让代码上线运行缓存更好使用。

配置方式在输出路径上修改文件名即可image-20210119010233477

14. tree shaking 和oneOf

1.oneOf

就是在module中配置loader,不想让loader多次匹配相同的文件就可以设置,但是要注意:需要两个loader处理同一个文件时就不能将这两个loader都放在oneOf中

//将只需要匹配一次的loader对象放在oneOf这个数组中,然后再把oneOf放在一个对象中 
module: {
    rules: [
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 优先执行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        // 以下loader只会匹配一个
        // 注意:不能有两个配置处理同一种类型文件
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          /*
            正常来讲,一个文件只能被一个loader处理。
            当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
              先执行eslint 在执行babel
          */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: { version: 3 },
                    targets: {
                      chrome: '60',
                      firefox: '50'
                    }
                  }
                ]
              ],
              // 开启babel缓存
              // 第二次构建时,会读取之前的缓存
              cacheDirectory: true
            }
          },
          {
            test: /\.(jpg|png|gif)/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              outputPath: 'imgs',
              esModule: false
            }
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              outputPath: 'media'
            }
          }
        ]
      }
    ]
  },

2. tree shaking

tree shaking: 去除无用代码 css或者js
前提: 1. 必须使用es6模块化,2.开启production环境

15.code split

code split 代码分割,主要是js代码分割

方式一

通过配置多个入口文件实现代码分割,注意之前的入口文件不需要对其他js文件进行引入

entry: {
    //多入口
    main: './src/js/index.js',
    test: './src/js/test.js'
  },
output: {
    //名字设置  如mian打包后就为main[hash]
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },       

打包后路径如下:
image-20210119011836871

方式二

在方式一的基础桑将node_modules中的代码单独打包成一个chunk最终输出,避免多个文件引用同一个资源时打包造成重复引入
webpack.config.js配置如下:

//和entry同级添加
optimization: {
    splitChunks: {
      chunks: 'all'
    },
    // 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
    // 解决:修改a文件导致b文件的contenthash变化
    runtimeChunk: {
      name: entrypoint => `runtime-${entrypoint.name}`
    },
  },

这里我在index.js中引入了node_modules中的jquery,打包后如下:
image-20210119012254298

方式三

不想通过多入口文件的方式实现js文件打包分离,这里我保留了方式二中的对node_modules打包的设置。
那么我们需要用到懒加载模式 需要我们自行在index.js中编写js代码

代码如下:

function sum(...args) {
    return args.reduce((p, c) => p + c, 0);
  }

/* 通过js代码来实现将test单独打包成一个chunk */

import(/* webpackChunkName: 'test' */'./test').then(({mul}) => {
  // eslint-disable-next-line
  console.log('加载成功');
  // eslint-disable-next-line
  console.log(mul(9,8));
}).catch(() => {
  // eslint-disable-next-line
  console.log('加载失败');
})


// eslint-disable-next-line
console.log(sum(1, 2, 3, 4, 5));

打包后的文件目录:
image-20210119012732438

16.懒加载

就是使用import()对需要进入的文件进行懒加载或者预加载

样例代码如下:

console.log('index.js文件加载了~~~');
document.getElementById('loader').addEventListener('click', function () {

//懒加载 ,当文件需要的时候再加载
//预加载,会提前加载js文件
//正常加载为并行加载(同一时间加载多个文件)  预加载可以理解为空闲时间偷偷加载,当然这个技术兼容性有些问题
    //这里面的注释就是分离文件的命名和是否开启预加载
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
    console.log(mul(32, 4))
  });
  ;
})

17 . PWA

PWA技术渐进式网络开发应用程序(离线可访问)

依赖 workbox库 npm i workbox-webpack-plugin -D

webpack.config.js配置如下:

//引入后在plugins中添加配置
new workboxWebpackPlugin.GenerateSW({
      /* 
        1.帮助serviceworker快速启动
        2.删除旧的serviceworker
        打包会生成一个关于serviceworker的配置文件
      */
      clientsClaim: true,
      skipWaiting: true
    })

入口文件配置如下:

/* 1. 注意eslint不认识window啥的变量需要再package.json中添加修改配置
    "eslintConfig": {
    "extends": "airbnb-base",
    "env": {
      "browser": true
    }
  }
  在之前的基础上加上env的配置,这里设置环境变量为浏览器,也可以设置环境变量为node
  2. serviceworker代码必须在服务器上运行
  我觉得可以使用liveserver
  也可以使用nodejs来写个服务器
  也可以下载依赖 npm i server -g  然后命令 serve -s build 表示把build这个文件中的静态资源暴露出去, 默认端口为5000
*/
// 注册serviceworker
// 处理兼容问题
if ('serviceWorker' in navigator) { // 判断是否存在
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(() => {
        console.log('serviceworker注册成功~~~~~');
      })
      .catch(() => {
        console.log('serviceworker注册失败!!!!!');
      });
  });
}

18.多线程打包

下载依赖 npm i thread-loader -D

在希望多线程打包的文件下添加这个loader
如在babel-loader这里配置下:

{
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              /* 
                开启多进程打包。 
                进程启动大概为600ms,进程通信也有开销。
                只有工作消耗时间比较长,才需要多进程打包
              */
              {
                loader: 'thread-loader',
                options: {
                  workers: 2 // 进程2个
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: { version: 3 },
                        targets: {
                          chrome: '60',
                          firefox: '50'
                        }
                      }
                    ]
                  ],
                  // 开启babel缓存
                  // 第二次构建时,会读取之前的缓存
                  cacheDirectory: true
                }
              }
            ]
          },

19.externals

将一些不需要的库排除出去,打包时会忽略掉

直接在webpack.config.js中配置

//entry同级添加
externals: {//将一些不需要的东西排除出去,不打包到一起
    //忽略库名 --属性名是包名,值是页面引入jq的时候提供的变量(对象)
    jquery: 'jQuery'
  }

这样我在index.js引入的jq就不会被打包,但是我们换成cdn的形式,需要我们自己手动在html中去添加

20. dll

dll与externals类似也是对第三方库进行打包
步骤一:我们首先要创建一个与webpack.comfig.js同级的webpack.dll.js文件

添加如下代码:

/* 
  使用dll技术对某些第三方库进行打包
  当你运行 webpack 时,默认查找 webpack.config.js 配置文件
    需求:需要运行 webpack.dll.js 文件
      --> webpack --config webpack.dll.js
 */
const { resolve } = require('path');
const webpack = require('webpack');
 module.exports = {
   entry: {
     //最终打包生成的name
     jquery: ['jquery']
   },
   output: {
     filename: '[name].js',
     path: resolve(__dirname,'dll'),
     library: '[name]_[hash]'//打包的库里面向外暴露出去的内容叫什么
   },
   plugins: [ 
     //打包生成一个manifest.json --> 提供jquery的映射
     new webpack.DllPlugin({
       name: '[name]_[hash]',//映射的库的暴露的内容名称
       path: resolve(__dirname,'dll/manifest.json')//输出的文件目录
     })
   ],
   mode: 'production'
 }

这个时候我们需要执行这个文件中的内容,所以输入命令 webpack --config webpack.dll.js
之后会在与src同级目录下生成一个dll文件其中就包含一个jquery.js(我们这里只引入了jquery),和一个manifest.json

步骤二:在webpack.config.js中添加配置
代码如下:

const { resolve } = require('path');

const htmlWebpackPlugin = require('html-webpack-plugin');//插件需要引入使用
const webpack = require('webpack');//首先要引webpack这个库
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');//这个插件要单独下载
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname,'build')
  },
  module: {
    rules: [
      {

      }
    ]
  },
  plugins: [
    //默认会创建一个空html,会引入其他的打包js和样式资源
    new htmlWebpackPlugin({
      //会复制index.html的结构,同时引入其他的打包js和样式资源
      template: './src/index.html'
    }),
    //告诉webpack那些库不参与打包,同时使用时名称也得改
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname,'dll/manifest.json')
    }),
    //将某个文件打包输出出去,并在html中自动引入该资源
    new addAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname,'dll/jquery.js')
    })
  ],
  mode: 'production'
}

这时我们在运行webpack 打包在build中jquery就会单独被打包,然后引入html文件中

image-20210119212136925

image-20210119212201256

Last modification:January 19, 2021
如果觉得我的文章对你有用,请随意赞赏