webpack4相关

简介

webpack 是一个静态模块打包器。(v4.41)
入口js文件(引入JQ、less等chunk块)-->less转为css/es6转为es5-->打包后输出为bundle。

1.1 五个核心概念

入口(Entry)

输出(Output)

Loader :webpack 去处理那些非 JavaScript 文件 (webpack 自 身 只 理 解 JavaScript)

插件(Plugins):可以用于执行范围更广的任务 

模式(Mode):development/production
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/*
  entry: 入口起点
    1. string --> './src/index.js'
      单入口:打包形成一个chunk, 输出一个bundle文件。
        -->此时chunk的名称默认是 main
    2. array  --> ['./src/index.js', './src/add.js']
      多入口:所有入口文件最终只会形成一个chunk, 输出一个bundle文件。
        --> 只有在HMR功能中让html热更新生效~
    3. object
      多入口:有几个入口文件就形成几个chunk,输出几个bundle文件
        -->此时chunk的名称是 key
*/

module.exports = {
  entry: {
    index: ['./src/index.js', './src/count.js'], 
    add: './src/add.js'
  },
  output: {
    // 文件名称(指定名称+目录)---主文件
    filename: 'js/[name].js',
    // 输出文件目录(将来所有资源输出的公共目录)
    path: resolve(__dirname, 'build'),
    // 所有资源引入公共路径前缀 --> 'js/built.js' --> '/js/built.js'
    publicPath: '/',
    publicPath: 'http://cdn.abc.com'  // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到
    chunkFilename: 'js/[name]_chunk.js', // 非入口chunk的名称:0_chunk.js(import引入的方式)---chunk方式命名表示非主文件
    //assetModuleFilename: "static/media/[name].[hash][ext]", // 图片、字体等资源命名方式(注意用hash)
    // library: '[name]', // 整个库向外暴露的变量名main
    // libraryTarget: 'window' // 变量名添加到哪个上 browser
    // libraryTarget: 'global' // 变量名添加到哪个上 node
    // libraryTarget: 'commonjs'
  },
  module: {
    rules: [
      // loader的配置
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']// 多个loader用use
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,// 排除node_modules下的js文件
        include: resolve(__dirname, 'src'),// 只检查 src 下的js文件
        enforce: 'pre',// 优先执行;post延后执行
        loader: 'eslint-loader',// 单个loader用loader
        options: {}
      },
      {
        // 以下配置只会生效一个
        oneOf: []
      }
    ]
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development'
};

1.2 基本使用

npm install webpack webpack-cli -D
开发环境指令 webpack src/js/index.js -o build/js/built.js --mode=development
        功能:webpack 能编译打包 js json 文件,并将 es6 的模块化语法转换成浏览器能识别的语法。
生产环境指令 webpack src/js/index.js -o build/js/built.js --mode=production
        功能:在开发配置功能上多一个功能,压缩代码。

开发环境的基本配置

2.1 配置

打包样式资源:less-loader  css-loader  style-loader

打包html资源: html-webpack-plugin

处理图片资源:url-loader  html-loader

处理其他资源:file-loader

devServer:webpack-dev-server

2.2 编码

/*
  开发环境配置:能让代码运行
    运行项目指令:
      webpack 会将打包结果输出出去
      npx webpack-dev-server 只会在内存中编译打包,没有输出
*/

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')// 输出路径:__dirname代表当前文件的目录绝对路径
  },
  module: {
    rules: [
      // loader的配置
      {
        // 处理less资源
        test: /\.less$/,// 匹配哪些文件
        //less-loader:将less文件编译成css文件
        //css-loader:将css文件变成commonjs模块加载js中
        //style-loader:创建style标签,将js中的样式添加到head中生效
        use: ['style-loader', 'css-loader', 'less-loader']// use数组中loader执行顺序:从右到左,从下到上依次执行
      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理sass资源:安装sass-loader sass
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
        // 处理stylus资源:安装stylus-loader
        test: /\.styl$/,
        use: ["style-loader", "css-loader", "stylus-loader"],
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',//依赖于file-loader
        options: {
          limit: 8 * 1024,// 图片大小小于8kb,就会被base64处理;减少请求数量,图片体积会更大
          name: '[hash:10].[ext]',// [hash:10]取图片的hash的前10位 [ext]取文件原来扩展名
          esModule: false,// 关闭es6模块化:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'//引入图片,从而被url-loader处理
      },
      {
        // 处理其他资源(如图标字体)
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({//默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
      template: './src/index.html'// 复制 './src/index.html' 文件
    })
  ],
  mode: 'development',
  devServer: {// 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
    contentBase: resolve(__dirname, 'build'),// 项目构建后路径
    watchContentBase: true,// 监视 contentBase 目录下的所有文件,一旦文件变化就会 reload
    watchOptions: {
      ignored: /node_modules/ // 忽略文件
    },    
    compress: true,// 启动gzip压缩
    host: 'localhost',// 域名
    port: 3000,
    open: true// 自动打开浏览器
    hot: true,// 开启HMR功能
    clientLogLevel: 'none',// 不要显示启动服务器日志信息
    quiet: true,// 除了一些基本启动信息以外,其他内容都不要显示
    overlay: false,// 如果出错了,不要全屏提示~
    proxy: {// 服务器代理 --> 解决开发环境跨域问题
      // 一旦devServer(5000)服务器接受到 /api/xxx 的请求,就会把请求转发到另外一个服务器(3000)
      '/api': {
        target: 'http://localhost:3000',
        // 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api)
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  },
  resolve: {// 解析模块的规则
    // 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
    alias: {
      $css: resolve(__dirname, 'src/css')
    },
    // 配置省略文件路径的后缀名
    extensions: ['.js', '.json', '.jsx', '.css'],
    // 告诉 webpack 解析模块是去找哪个目录(node_modules)
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  }
};

3 生产环境的基本配置

3.1 配置

提取css为单独文件:min-css-extract-plugin

  • Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式。这样对于网站来说,会出现闪屏现象
  • 我们应该是单独的 Css 文件,通过 link 标签加载性能才好。

css兼容性处理:postcss-loader  postcss-preset-env postcss

压缩css:optimize-css-assets-webpack-plugin

js语法检查:eslint-loader  eslint  eslint-config-airbnb-base eslint-plugin-import

js兼容性处理

        babel-loader @babel/core @babel/preset-env(基本语法)core-js(高级语法按需加载)

        @babel/polyfill:promise可以,兼容性代码全部引入,体积太大。入口文件直接引入

压缩html: html-webpack-plugin

3.2 编码

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');

// 定义nodejs环境变量:决定使用browserslist的哪个环境,默认为生产环境
process.env.NODE_ENV = 'production';

// 复用loader
        /*
          "browserslist": {
              // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
              "development": [
                "last 1 chrome version",
                "last 1 firefox version",
                "last 1 safari version"
              ],
              // 生产环境:默认是看生产环境
              "production": [
                ">0.2%",
                "not dead",
                "not op_mini all"
              ]
            }
          */
const commonCssLoader = [
  MiniCssExtractPlugin.loader,// 这个loader取代style-loader。作用:提取js中的css成单独文件。最终通过link引入,减小js文件的体积,还可以避免闪屏
  'css-loader',
  {
    // 还需要在package.json中定义browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]//帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [...commonCssLoader]
      },
      {
        test: /\.less$/,
        use: [...commonCssLoader, 'less-loader']
      },
      /*
        1.正常来讲,一个文件只能被一个loader处理。当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:先执行eslint 在执行babel。
        2.在package.json中eslintConfig设置检查规则 --> airbnb--> eslint-config-airbnb-base  eslint-plugin-import eslint
              "eslintConfig": {
                "extends": "airbnb-base"
              }
      */
      {//js语法检查
        test: /\.js$/,
        exclude: /node_modules/,//只检查自己写的源代码
        enforce: 'pre',// 优先执行
        loader: 'eslint-loader',//依赖于eslint
        options: {
          fix: true// 自动修复eslint的错误
        }
      },
      {//js兼容性处理
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',//依赖于@babel/core
        options: {
          presets: [
            [
              '@babel/preset-env',//基本js兼容性处理
              {
                useBuiltIns: 'usage',// 按需加载
                corejs: {version: 3},// 指定core-js版本
                targets: {// 指定兼容性做到哪个版本浏览器
                  chrome: '60',
                  firefox: '50',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ],
           cacheCompression: false, // 缓存文件不要压缩
           cacheDirectory: true// 开启babel缓存。第二次构建时,会读取之前的缓存
        }
      },
      {
        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'
        }
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({//提取css为单独文件
      filename: 'css/built.css',
      chunkFilename: "static/css/[name].chunk.css",
    }),
    new OptimizeCssAssetsWebpackPlugin(),// 压缩css
    new HtmlWebpackPlugin({// 压缩html代码
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,// 移除空格
        removeComments: true// 移除注释
      }
    })
  ],
  mode: 'production'// 压缩js
  optimization: {
    splitChunks: {
      chunks: 'all'
      // 以下注释部分为默认值,可以不写~
      /* minSize: 30 * 1024, // 分割的chunk最小为30kb
      maxSiza: 0, // 最大没有限制
      minChunks: 1, // 要提取的chunk最少被引用1次
      maxAsyncRequests: 5, // 按需加载时并行加载的文件的最大数量
      maxInitialRequests: 3, // 入口js文件最大并行请求数量
      automaticNameDelimiter: '~', // 名称连接符
      name: true, // 可以使用命名规则
      cacheGroups: {
        // 分割chunk的组
        // node_modules文件会被打包到 vendors 组的chunk中。--> vendors~xxx.js
        // 满足上面的公共规则,如:大小超过30kb,至少被引用一次。
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          // 优先级
          priority: -10
        },
        default: {
          // 要提取的chunk最少被引用2次
          minChunks: 2,
          // 优先级
          priority: -20,
          // 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
          reuseExistingChunk: true
        } 
      }*/
// 缓存分组
            cacheGroups: {
                // 第三方模块
                vendor: {
                    name: 'vendor', // chunk 名称
                    priority: 1, // 权限更高,优先抽离,重要!!!
                    test: /node_modules/,
                    minSize: 0,  // 大小限制
                    minChunks: 1  // 最少复用过几次
                },

                // 公共的模块
                common: {
                    name: 'common', // chunk 名称
                    priority: 0, // 优先级
                    minSize: 0,  // 公共模块的大小限制
                    minChunks: 2  // 公共模块最少复用过几次
                }
            }
    },
    // 问题:修改a文件导致b文件(import导入a文件)的contenthash变化,打包生成a和b(包含a文件名的映射关系)
    runtimeChunk: {// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
      name: entrypoint => `runtime-${entrypoint.name}`//打包后生成b/a/a_runtime文件
    },
    minimizer: [// 配置生产环境的压缩方案:js和css
      new TerserWebpackPlugin({
        // 开启缓存
        cache: true,
        // 开启多进程打包
        parallel: true,
        // 启动source-map
        sourceMap: true
      })
    ]
  }
};

3.3 配置合并

const webpackCommonConf = require('./webpack.common.js')
const { smart } = require('webpack-merge')

module.exports = smart(webpackCommonConf, {
    mode: 'development',
    }
})

4 性能优化

开发:打包速度HMR、代码调试sourceMap

生产:打包速度oneOf、babel缓存、多进程打包、externals、dll、

           代码性能:文件资源缓存、tree shaking、code split、懒加载、pwa

4.1 开发环境

HMR: hot module replacement 热模块替换 / 模块热替换

问题:npx xxx 启动开发环境配置--->修改代码,整个页面会重新刷新
作用:devServer中开启hot--->一个模块发生变化,只会重新打包这一个模块

/*
  
      样式文件:可以使用HMR功能:因为style-loader内部实现了~
      js文件:默认不能使用HMR功能 --> 修改index.js中的代码,根据hot属性存在,监听模块文件变化更新
              注意:HMR功能只能处理非入口js文件 。
      html文件: 默认不能使用HMR功能,同时会导致问题:html文件不能热更新了~ (不用做HMR功能)
              解决:修改entry入口,将html文件引入
*/

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

module.exports = {
  entry: ['./src/js/index.js', './src/index.html'],
  output: {},
  module: {},
  plugins: [],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 开启HMR功能
    // 当修改了webpack配置,新配置要想生效,必须重新webpack服务
    hot: true
  }
};

index.js

if (module.hot) {
  module.hot.accept('./print.js', function() {
    // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
    // 会执行后面的回调函数
    print();
  });
}

source-map: 一种提供源代码到构建后代码映射技术,打包后生成js.map文件,快速定位源代码的错误位置。

开发环境:速度快,调试好 eval-source-map(内联)

生产环境:源代码隐藏,调试友好 source-map(外部js.map)

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

module.exports = {
  entry: ['./src/js/index.js', './src/index.html'],
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: []
  },
  plugins: [],
  mode: 'development',
  devServer: {},
  devtool: 'eval-source-map'//source-map
};

4.2 生产环境

module中配置oneOf:同类型的文件只匹配一个loader,将eslint-loader提取出去。

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

// 复用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        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']
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: {version: 3},
                    targets: {
                      chrome: '60',
                      firefox: '50'
                    }
                  }
                ]
              ]
            }
          },
        ]
      }
    ]
  },
  plugins: [],
  mode: 'production'
};

babel缓存(第二次构建读取缓存)

文件资源缓存(上线):server.js用express搭建服务器引入built静态资源-->被强制缓存

        hash: 每次wepack构建时会生成一个唯一的hash值。

        问题: 因为js和css同时使用一个hash值。如果重新打包,会导致所有缓存失效 (只改动一个文件)

       chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样

       问题: js和css的hash值还是一样的。因为css是在js中被引入的,所以同属于一个chunk

       contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',//js
    path: resolve(__dirname, 'build')
  },
  module: {},
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'//css
    }),
  ],
  mode: 'production',
};

tree shaking:去除无用代码,减少代码体积

前提:1. 必须使用ES6模块化  2. 开启production环境

注意:package.json中配置sideEffects:false(所有代码都可以tree shaking,可能把打包后的css文件去掉)需要配置sideEffects:["*.css"]
code split:将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。

     代码分割(Code Split)主要做了两件事:

  1. 分割文件:将打包生成的文件进行分割,生成多个 js 文件。
  2. 按需加载:需要哪个文件就加载哪个文件。
a.入口文件有几个,就生成几个bundle;(多入口)
b.配置了optimization中的chunks,将node_modules中代码单独打包一个chunk输出一个bundle;(第三方包:提取重复代码)
c.import动态导入语法:能将某个文件单独打包成一个chunk。(源代码:按需加载,动态导入)
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//方式一:
module.exports = {
  // 单入口:输出一个bundle
  // entry: './src/js/index.js',
  entry: {
    // 多入口:输出两个bundle
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};

//方式二:
module.exports = {
  // 单入口:输出两个个bundle
  // entry: './src/js/index.js',//引入JQ
  entry: {
    // 多入口:输出三个bundle
    index: './src/js/index.js',//引入JQ
    test: './src/js/test.js'//引入JQ
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /*
    1. 可以将node_modules中代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};

//方式三:
//在方式二的基础上,在入口文件中引入test.js
/*
  通过js代码,让某个文件被单独打包成一个chunk
  import动态导入语法:能将某个文件单独打包
*/
// eslint会对动态导入语法报错,需要修改eslint配置文件
// webpackChunkName: "test":这是webpack动态导入模块命名的方式,配合output中的chunkFileName使用
// "test"将来就会作为[name]的值显示。
import(/* webpackChunkName: 'test' */'./test')
  .then(({ mul, count }) => {
    // 文件加载成功~
    console.log(mul(2, 5));
  })
  .catch(() => {
    console.log('文件加载失败~');
  });

懒加载:当文件需要使用时才加载~

预加载:文件使用之前提前加载,其他资源加载完毕,浏览器空闲时加载。兼容性较差

  • Preload:告诉浏览器立即加载资源,兼容性较好。Prefetch:告诉浏览器在空闲时才开始加载资源。

  • Preload加载优先级高,Prefetch加载优先级低。
  • Preload只能加载当前页面需要使用的资源,Prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源。
document.getElementById('btn').onclick = function() {//点击按钮的时候加载index.js中的test.js
  //预加载:webpackPrefetch: true
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
    console.log(mul(4, 5));
  });
};

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

1.安装workbox-webpack-plugin,打包后会生成service-worker.js文件

2.入口文件注册配置文件,需要修改eslintConfig配置来支持浏览器全局变量

3.将build文件夹下静态文件通过服务器暴露出去

const { resolve } = require('path');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

/*
  PWA: 渐进式网络开发应用程序(离线可访问)
    workbox --> workbox-webpack-plugin
*/

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: { },
  plugins: [
    new WorkboxWebpackPlugin.GenerateSW({
      /*
        1. 帮助serviceworker快速启动
        2. 删除旧的 serviceworker

        生成一个 serviceworker 配置文件~
      */
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  mode: 'production',
};

/*
  1. eslint不认识 window、navigator全局变量
    解决:需要修改package.json中eslintConfig配置
      "env": {
        "browser": true // 支持浏览器端全局变量
      }
   2. sw代码必须运行在服务器上
      --> nodejs
      -->
        npm i serve -g
        serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
// index.js中注册serviceWorker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw注册成功了~');
      })
      .catch(() => {
        console.log('sw注册失败了~');
      });
  });
}

开启多进程打包:开启电脑的多个进程同时干一件事。我们想要继续提升打包速度,其实就是要提升 js 的打包速度,而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具。

        我们启动进程的数量就是我们 CPU 的核数。每个进程启动大概为600ms,进程通信也有开销,不要滥用

const { resolve } = require('path');
const os = require("os");// nodejs核心模块,直接使用
const threads = os.cpus().length;//cpu核数

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
        {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'thread-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'
                        }
                      }
                    ]
                  ],
                  cacheDirectory: true
                }
              }
            ]
          },
       ]
    },
  plugins: [],
  mode: 'production',
};

externals:配置忽略的库名,如JQ;此时JQ需要在html文件中通过CDN引入

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')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'production',
  externals: {
    jquery: 'jQuery'// 拒绝jQuery被打包进来
  }
};

使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包

webpack.dll.js

执行命令webpack --config webpack.dll.js

结果生成了jQuery.js和manifest.json文件,manifest用来提供和JQ映射

/*
    当你运行 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'] --> 要打包的库是jquery
    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.js

1.引入manifest.json文件,不再打包jq(jq部署到自己服务器上)

2.add-asset-html-webpack-plugin:将某个文件打包输出出去,并在html中自动引入该资源
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      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'
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值