webpack分析

镜像地址的配置

Posted by gankai on June 27, 2019

环境搭建:安装Node.js 和 NPM

安装nvm https://github.com/nvm-sh/nvm

ps: nvm(Node.js Version Manager)也就是 Node.js 的包管理器,可以通过它方便安装和切换不同的Node.js版本。
  • Mac通过 curl 安装:curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash

  • Windows的安装方法 参考这里

检查node和NPM版本安装成功如下:

环境搭建:安装webpack和webpack-cli

创建空目录和package.json

  • mkdir webpack.1-1
  • cd webpack.1-1
  • npm init -y

安装 webpack 和 webpack-cli

  • npm install webpack webpack-cli --save-dev

  • 检查是否安装成功 cd node_modules.bin> webpack -v

在项目根目录下创建一个webpack.config.js 文件


   const path = require('path');

   module.exports = {
     entry: './src/index.js',
     output: {
       path: path.join(__dirname, 'dist'),// 打包的文件夹名
       filename: 'bundle.js'    // 打包的文件名
     },
     mode: 'production'

   }

同时,在项目根目录下,创建src文件夹及其子文件`helloworld.js`和`index.js`

`helloworld.js`

   export function helloworld() {
     return 'hello webpack';
   }

`index.js`

   import { helloworld } from './helloworld';

   document.write(helloworld());

这样一个简单的demo就完成了,在工程命令行中执行命令 webpack开始打包工程。

打包好的结果是这样的:

由于我们打包出来的dist文件夹下面是没有html文件的,所以我们在dist文件夹下新建一个index.html文件,然后将bundle.js引进来。然后在浏览器中打开,一个简单的demo效果就出来了。

总结一下:

    'use strict';                                      

    const path = require('path');                    
                                                       
    module.exports = {                                     
      entry: './src/index.js', // 用来指定webpack的打包入口  // 如果是Windows电脑应该这样配置 entry: '../../src/index.js',                 
      output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'    // 打包的文件名
      },
      mode: 'production'

    }
`index.html`

    <!DOCTYPE html>
    <html lang="en">

    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Hello Webpack</title>
    </head>

    <body>
      <script src="./bundle.js" type="text/javascript"></script>
    </body>

    </html>

通过 npm script 运行 webpack

package.json文件中运行的脚本,默认是可以读取到 node_modules/.bin/下面的所以命令的通过npm run build 运行打包

原理:模块的局部安装会在node_modules/.bin目录下创建软链接

package.jsonscripts中添加一条脚本命令: "build":"webpack",

 {
   "name""webpack.1.2",
   "version""1.0.0",
   "description""通过 npm script 运行 webpack",
   "main""index.js",
   "scripts": {
     "build":"webpack",
     "test""echo \"Error: no test specified\" && exit 1"
   },
   "keywords": [],
   "author""",
   "license""ISC",
   "devDependencies": {
     "webpack""^4.35.3",
     "webpack-cli""^3.3.5"
   }
 }

通过在终端运行npm run build 即可完成打包项目。

webpack 核心概念之entry用法

webpack.config.js文件中:

  1. 单入口:entry是一个字符串。
 module.exports = {
  entry:'./src/file.js'
 }
  1. 多入口:entry是一个对象
 module.exports = {
  entry: {
   index: './src/index.js',
   search: './src/search.js'
  }
 }

webpack 核心概念之Output的用法

  1. Output用来告诉webpack如何将编译后的文件输出到磁盘
  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.join(__dirname, 'dist'),  // 单入口只要配置path和filename这两个参数
      filename: 'bundle.js'
    },
    mode:'production'
  }
  1. Output多入口配置
  module.exports = {
    entry: {
      index: './src/index.js',
      search: './src/search.js'
    },
    output: {
      filename: '[name].js',  // 通过占位符确保文件名称的唯一性
      path: __dirname + '/dist'
    },
    mode:'production'
  }

webpack 核心概念之loaders的用法

webpack的开箱即用只支持js和json两种文件类型,通过loaders去支持其他文件类型,并且将他们转化成有效的模块,并且可以添加到依赖图中,loaders本身是一个函数,接受源文件作为参数,返回转换后的结果。

常见的loaders

名称 描述
babel-loader 转换ES6ES7等新特性语法
css-loader 支持.css文件的加载和解析
less-loader 将less转换为css
ts-loader 将ts转换为js
file-loader 进行图片,字体等的打包
raw-loader 将文件以字符串的形式导入
thread-loader 多进程打包js和css
 module.exports = {
   entry: './src/index.js',
   output: {
     path: path.join(__dirname, 'dist'),
     filename: 'bundle.js'
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.txt$/, use: 'raw-loader'    // test 指定匹配规则 use 指定使用的loader名称
       }
     ]
   }
 }

webpack 核心概念之plugins的用法

插件用于bundle文件的优化,资源管理和环境变量注入,作用于整个构建过程

常见的plugins

名称 描述
CommonsChunkPlugin 将chunks相同的模块代码提取成公共js文件
CleanWebpackPlugin 清理构建项目
ExtractTextWebpackPlugin 将chunks相同的模块代码提取成公共js文件
CommonsChunkPlugin 将css从bundle文件里提取成独立的css文件
CopyWebpackPlugin 将文件或者文件夹拷贝到构建的输出目录
HtmlWebpackPlugin 创建html文件去承载输出的bundle
UglifyjsWebpackPlugin 压缩js
ZipWebpackPlugin 将打包出的资源生成一个Zip包

 module.exports = {
   entry: './src/index.js',
   output: {
     path: path.join(__dirname, 'dist'),
     filename: 'bundle.js'
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.txt$/, use: 'raw-loader'    // test 指定匹配规则 use 指定使用的loader名称
       }
     ]
   },
   plugins: [
     new HtmlWebpackPlugin({
       template: './src/index.html'  //  创建html文件去承载输出的bundle
     })
   ]
 }

webpack核心概念之mode的用法

概念:Mode用于指定当前的构建环境是:production , development ,还是 none 。设置mode的值,可以使用webpack在相应阶段的内置函数,默认值为production(webpack4.x以后才有的概念),如果是productin,webpack会默认开启一些在生产阶段才使用的内置功能,如下参考:

选项 描述
development 设置process.env.NODE_ENV的值为development,开启NameChunksPlugin和NameModulesPlugin
production 设置process.env.NODE_ENV的值为production,开启FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin,SideEffectsFlagPlugin和TerserPlugin
none 不开启任何优化选项

资源解析:解析ES6语法

首先,安装三个插件: npm i @babel/core @babel/preset-env babel-loader -D

ps: -D 是 --save-dev 的简称 -i 是 install 的简称。

在项目根目录下,新建.babelrc文件,配置如下:

 {
   "presets":[
     "@babel/preset-env",  // ES6解析成ES5语法
   ]
 }

在 webpack.config.js文件中,module对象中添加一个新的plugin,如下:

 'use strict';
 
 const path = require('path')
 
 module.exports = {
   entry: {
     index: './src/index.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: path.join(__dirname, 'dist')
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件  注意这个地方 千万不能写成'/\.js$/' 遇到过的坑
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       }
     ]
   }
 }

资源解析:解析React jsx

首先安装相关依赖: npm i react react-dom @babel/preset-react -D

在src文件下新建search.js文件用于接下来的测试:

 
 'use strict';
 
 import React from 'react';
 import ReactDOM from 'react-dom';
 
 import logo from './images/webpack.jpg'
 import './search.less'
 class Search extends React.Component {

   render() {
     return <div className='search-text'>
       search page
       <img src={logo}/>
     </div>;
   }

 }
 
 ReactDOM.render(
   <Search />,
   document.getElementById('root')
 );

在.babelrc中增加React的babel preset的配置

 {
   "presets":[
     "@babel/preset-env",  // ES6解析成ES5语法
     "@babel/preset-react"  // 增加React的babel preset设置
   ]
 }

资源解析:解析css

安装:npm i style-loader css-loader -D

css-loader用于加载.css文件,并且转化成commonjs对象,style-loader将样式通过<style>标签插入到head中。

`webpack.config.js`

 'use strict';
 
 const path = require('path')
 module.exports = {
   entry: {
     index: './src/index.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: path.join(__dirname, 'dist')
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       }, {
         test: /\.css$/,
         use: ['style-loader''css-loader']  // 注意 解析顺序是从右往左的,先解析css-loader 后解析style-loader将css插入dom中。 
       }
     ]
   }
 }

资源解析:解析less

less-loader 用于将less转换成css,安装 npm i less less-loader -D

`webpack.config.js`
 
 'use strict';
 
 const path = require('path')
 module.exports = {
   entry: {
     index: './src/index.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: path.join(__dirname, 'dist')
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       },
       {
         test: /\.css$/,
         use: [ // 注意 解析顺序是从右往左的,先解析css-loader 后解析style-loader将css插入dom中。 
           'style-loader',
           'css-loader'
         ]
       },
       {
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           'less-loader'    // 用于解析less 
         ]
       }
     ]
   }
 }

资源解析:解析字体。

安装 npm install file-loader -D

search.less中添加字体:

 @font-face {
   font-family: 'SourceHanSerifSC-Heavy';
   src: url('./font-family/SourceHanSerifSC-Heavy.otf') format('truetype')
 }
 .search-text {
   text-align: center;
   font-size: 20px;
   color: red;
   font-family: 'SourceHanSerifSC-Heavy';
 }

然后在webpack.config.js中配置:file-loader

 'use strict';
 
 const path = require('path')
 module.exports = {
   entry: {
     index: './src/index.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: path.join(__dirname, 'dist')
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       },
       {
         test: /\.css$/,
         use: [ // 注意 解析顺序是从右往左的,先解析css-loader 后解析style-loader将css插入dom中。 
           'style-loader',
           'css-loader'
         ]
       },
       {
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           'less-loader'    // 用于解析less 
         ]
       },
       {
         test: /\.(png|jpg|gif|jpeg)$/,  // 解析图片和字体
         use: 'file-loader'
       }
     ]
   }
 }

资源解析:解析图片。

url-loader 安装 npm i url-loader -D

如下图所示,在没有使用url-loader之前, search.js大小是125KiB,图片大小是16.2KiB

配置url-loader

webpack.config.js

 'use strict';
 
 const path = require('path')
 module.exports = {
   entry: {
     index: './src/index.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: path.join(__dirname, 'dist')
   },
   mode: 'production',
   module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       },
       {
         test: /\.css$/,
         use: [ // 注意 解析顺序是从右往左的,先解析css-loader 后解析style-loader将css插入dom中。 
           'style-loader',
           'css-loader'
         ]
       },
       {
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           'less-loader'    // 用于解析less 
         ]
       },
       {
         test: /\.(png|jpg|gif|jpeg)$/,
         use: [
           {
             loader:'url-loader',
             options:{
               limit:20480 // 如果一张图片小于20k webpack将自动将图片转为base64打包进文件,如果超过这个大小,将单独打包。
             }
           }
         ]
       },
       {
         test: /\.(woff|woff2|eot|ttf|otf)$/,
         use: 'file-loader'
       }
     ]
   }
 }

当配置了url-loader之后,webpack已经将大小为16.2KiB大小的图片(小于我们的限制),打包进search.js中了,search.js从之前的125kib大小变成了147kib,大约增加了16.2kib大小。

webpack中的文件监听

文件监听是在发现源码发生变化的时候,自动重新构建出新的输出文件。

webpack开启监听模式的两种模式:

  • 启动 webpack 命令时候,带上 --watch 参数

package.json中配置如下:

"scripts": {
    "build": "webpack --watch"
},

上面方式有个缺陷,就是每次webpack更新代码,都要手动刷新浏览器!

  • 在配置 webpack.config.js 中设置 watch:true

通过轮询判断文件的最后编辑时间,是否发生变化,当某个文件发生变化,并不会立即告诉监听者,而是先缓存起来,等aggregateTimeout。

   module.exports = {
     // 默认是false ,不开启状态
     watch: true,
     // 只有开启监听模式watchOptions才有意义
     watchOptions: {
       // 不监听的文件或者文件夹,默认为空,支持正则匹配。
       ignored: /node_modules/,
       // 监听到变化发生后,会等300ms再去执行更新,默认是300ms 
       aggregateTimeout: 300,
       // 判断文件是否发生变化,是通过不停的询问系统指定文件有没有发生变化实现的,默认每秒问1000次。
       poll: 1000
     },
   } 

webpack中的热更新:webpack-dev-server及其原理

首先安装: npm i webpack-dev-server -D

package.json 中配置如下:

 "scripts": {
    "dev": "webpack-dev-server --open" 
  },

webpack.config.js中配置:

 const webpack = require('webpack');
 module.exports = {
   mode: 'development',   // 开发环境
   plugins: [
      // webpack 自带的热更新插件
      new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
      contentBase: './dist',  // webpack服务的基础目录
      hot: true
    }
 }

webpack中的热更新:webpack-dev-middleware(WDM)及其原理。

WDM将webpack输出的文件传输服务器,适用于灵活的应用场景。

 const express = require('express'); 
 const webpack = require('webpack'); 
 const webpackDevMiddleware = require('webpack-devmiddleware');
 const app = express(); 
 const config = require('./webpack.config.js'); const compiler = webpack(config);
 app.use(webpackDevMiddleware(compiler, { publicPath: config.output.publicPath
 }));
 app.listen(3000, function () { 
 console.log('Example app listening on port 3000!\n');
 });

原理分析

webpack compile: 将js编译成,bundle.js

HMR Server:将热更新的文件输出给 HMR Runtime

Bundle server: 提供文件在浏览器的访问

HMR runtime: 会被注入到浏览器,更新文件的变化。

bundle.js:构建输出的文件

原理图如下所示:

文件指纹策略

打包后输出的文件名的后缀

文件指纹如何生成?

  • hash:整个项目的构建相关,只要项目文件有修改,整个项目的构建的hash就会改变。
  • Chunkhash:和webpack打包的chunk有关,不同的entry会生成不同的chunkhash值。
  • contenthash:根据文件内容来定义hash,文件内容不变,则contenthash不变。

js的文件指纹的设置

设置 output 的 filename,使用 [chunkhash]

 module.exports = {
  output: {
   filename: '[name]_[chunkhash:8].js',
   path: path.join(__dirname, 'dist')
  },
 }

css的文件指纹的设置

设置MiniCssExtractPlugin的filename,使用[contenthash]

占位符名称 含义
[ext] 资源后缀名
[name] 文件名称
[path] 文件的相对路径
[folder] 文件所在的文件夹
[contenthash] 文件的内容hash,默认是md5生成
[hash] 文件的内容hash,默认是md5生成
[emoji] 一个随机的指代文件内容的emoji

首先安装插件 npm install mini-css-extract-plugin -D

在新建的 webpack.prod.js文件中配置:

 module: {
     rules: [
       {
         test: /\.js$/,     // 匹配js文件
         use: 'babel-loader' // 用于将ES6等高级语法解析成ES5语法
       },
       {
         test: /\.css$/,
         use: [ // 注意 解析顺序是从右往左的,先解析css-loader 后解析style-loader将css插入dom中。 
           // 'style-loader',
           MiniCssExtractPlugin.loader, // MiniCssExtractPlugin是将css代码提取出来,这两个loader不能同时使用。
           'css-loader'
         ]
       },
       {
         test: /\.less$/,
         use: [
           // 'style-loader',
           MiniCssExtractPlugin.loader, // MiniCssExtractPlugin是将css代码提取出来,这两个loader不能同时使用。
           'css-loader',
           'less-loader'    // 用于解析less 
         ]
       },
       {
         test: /\.(png|jpg|gif|svg|jpeg)$/,
         use: [
           {
             loader: 'file-loader',  // file-loader 和url-loader都行
             options: {
               name: '[name]_[hash:8][ext]'
             }
           }
         ]
       },
       {
         test: /\.(woff|woff2|eot|ttf|otf)$/,
         use: [
           {
             loader: 'file-loader',  // file-loader 和url-loader都行
             options: {
               name: '[name]_[hash:8][ext]'
             }
           }
         ]
       }
     ]
   },

webpack 的代码的压缩

js文件的压缩

webpack 内置了,uglifyjs-webpack-plugin在打包代码的时候,会自动压缩js代码。

css 文件的压缩

使用optimize-css-assets-webpack-plugin,同时使用需要依赖 cssnano预处理器

安装 npm i optimize-css-assets-webpack-plugin cssnano -D

webpack.prod.js中配置plugins:

 const OptimizeCssAssetsWebpackPlugin = requir('optimize-css-assets-webpack-plugin')

 plugins: [
  new OptimizeCssAssetsWebpackPlugin({
   assetNameRegExp:/.css$/g,
   cssProcessor: require('cssnano')
  })
 ],

执行 npm run build 查看压缩效果

html文件的压缩

首先安装插件: npm i html-webpack-plugin -D

webpack.prod.js配置文件中配置:

 const HtmlWebpackPlugin = require('html-webpack-plugin')
    plugins: [
        new MiniCssExtractPlugin({
          filename: `[name]_[contenthash:8].css`
        }),
        new OptimizeCssAssetsWebpackPlugin({
          assetNameRegExp: /.css$/g,
          cssProcessor: require('cssnano')
        }),
        new HtmlWebpackPlugin({  // 通常一个html页面用一个HtmlWebpackPlugin,如果有两那就写两个
          template: path.join(__dirname, 'src/index.html'),  //html模板所在的位置
          filename: 'index.html',// 指定打包出来的html文件名称
          chunks: ['index'],// chunk名称 指定生成的html要使用哪些chunk
          inject: true,// 是否将打包出来的js或者css将自动注入到index.html中
          minify: {
            html5: true,
            collapseWhitespace: true,
            preserveLineBreaks: false,
            minifyCSS: true,
            minifyJS: true,
            removeComments: false
          }
        }),
        new HtmlWebpackPlugin({  // 通常一个html页面用一个HtmlWebpackPlugin,如果有两那就写两个
          template: path.join(__dirname, 'src/search.html'),  //html模板所在的位置
          filename: 'search.html',// 指定打包出来的html文件名称
          chunks: ['search'],// chunk名称 指定生成的html要使用哪些chunk
          inject: true,// 是否将打包出来的js或者css将自动注入到search.html中
          minify: {
            html5: true,
            collapseWhitespace: true,
            preserveLineBreaks: false,
            minifyCSS: true,
            minifyJS: true,
            removeComments: false
          }
        }),
      ],

执行 npm run build 查看压缩效果

自动清理构建目录

npm install clean-webpack-plugin -D 避免在每次构建的时候,都需要手动清理dist文件。

webpack.dev.js中配置如下:

    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    // 这个地方注意,可能会报错必须用解构的方式

`plugins`下添加如下代码:` new CleanWebpackPlugin()`执行npm run build 打包构建

### 自动补全css3前缀,autoprefixer

先安装插件:`npm i postcss-loader autoprefixer -D`

在`webpack.prod.js`的module中配置如下:

    {
        test: /\.less$/,
        use: [
        // 'style-loader',
        MiniCssExtractPlugin.loader, // MiniCssExtractPlugin是将css代码提取出来,这两个loader不能同时使用。
        'css-loader',
        'less-loader', // 用于解析less
        {
            loader: 'postcss-loader',
            options: {
              plugins: () => [
                require('autoprefixer')({
                  browsers: ['last 2 version''>1%''ios 7 ']
                })
              ]
            }
        }
        ]
    },

移动端CSS px自动转化成rem

安装插件:npm i px2rem-loader -D 到开发环境中,再直接引用npm i lib-flexible -S

    {
        loader: 'px2rem-loader',
        options: {
            remUnit: 75, // 1rem == 75px
            remPrecision: 8 // 当px转换为rem的时候,小数点后面的位数。
        }
    }

然后将flexble.js 内联进我们的html中!

静态资源内联

资源内联的意义:

  • 页面框架的初始化脚本
  • 上报相关打点
  • css内联避免页面闪动

raw-loader内联html

<script>${require('raw-loader!./meta.html')}</script>

安装 npm i raw-loader@0.5.1 -D

raw-loader内联js

<script>${require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js')}</script>

css内联

  • 借助 style-loader
  • 借助 html-inline-css-webpack-plugin

配置如下:

    // 'style-loader',
    {
      loader: 'style-loader',
        options: {
          insertAt: 'top', // 样式插入到<head>中
          singleton: true // 将所有的style标签合并成一个
        }
    },

多页面应用(MPA)概念,多页面打包通用方案

动态获取entry和设置html-webpack-plugin数量利用global.sync

安装glob npm i glob -D

webpack.prod.js文件中配置如下:

    const glob = require('glob')
        const setMPA = () => {
        const entry = {}
        const htmlWebpackPlugin = []
        const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'))
        Object.keys(entryFiles).map(index => {
            const entryFile = entryFiles[index]
            const match = entryFile.match(/src\/(.*)\/index\.js/)
            const pageName = match && match[1]
            entry[pageName] = entryFile
            htmlWebpackPlugin.push(
            new HtmlWebpackPlugin({ // 通常一个html页面用一个HtmlWebpackPlugin,如果有两那就写两个
                template: path.join(__dirname, `src/${pageName}/index.html`), // html模板所在的位置
                filename: `${pageName}.html`, // 指定打包出来的html文件名称
                chunks: [pageName], // chunk名称 指定生成的html要使用哪些chunk
                inject: true, // 是否将打包出来的js或者css将自动注入到index.html中
                minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
                }
            })
            )
        })
        return {
            entry,
            htmlWebpackPlugin
        }
    }
    const { entry, htmlWebpackPlugin } = setMPA()

    module.exports = {
        entry,
        plugins: [
        new MiniCssExtractPlugin({
            filename: `[name]_[contenthash:8].css`
        }),
        new OptimizeCssAssetsWebpackPlugin({
            assetNameRegExp: /.css$/g,
            cssProcessor: require('cssnano')
        }),
            new CleanWebpackPlugin()
        ].concat(htmlWebpackPlugin)
    }    

使用source map

作用:通过source map定位到源代码,开发环境开启,线上环境关闭,线上排查问题的时候,可以将问题上传到错误监控系统

sourcemap 关键字

  • eval 使用eval包裹模块代码
  • sourcemap 产生.map 文件
  • cheap 不包含列信息(当代码报错的时候,只显示报错位置所在的行信息)
  • inline 将.map作为DataURI嵌入,不单独成.map文件
  • module 包含loader的sourcemap

sourcemap类型

devtool 首次构建 二次构建 是否适合生产环境 可以定位的代码
(none) +++ +++ yes 最终输出的代码
eval +++ +++ no webpack生产的代码(一个个的模块)
cheap-eval-source-map + ++ no 经过loader转换后的代码(只能看到行)
cheap-module-source-map o ++ no 源代码(只能看到行)
eval-source-map -- + no 源代码
cheap-source-map + o yes 经过loader转换后的代码(只能看到行)
cheap-module-source-map o - yes 源代码(只能看到行)
inline-source-map + o no 经过loader转换后的代码(只能看到行)
inline-cheap-module-source-map o - no 源代码(只能看到行)
source-map -- -- yes 源代码
inline-source-map -- -- no 源代码
hidden-source-map -- -- yes 源代码

提取页面公共资源

先安装: npm i html-webpack-externals-plugin -D

新增react的开发环境的CDN:

    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

一下是react的线上环境的CDN:

    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

webpack.prod.js中配置线上环境的CDN:

    const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')

plugins中:

    new HtmlWebpackExternalsPlugin({
      externals: [
        {
          module: 'react',
          entry: 'https://unpkg.com/react@16/umd/react.production.min.js',
          global: 'React'
        },
        {
          module: 'react-dom',
          entry: 'https://unpkg.com/react-dom@16/umd/react-dom.production.min.js',
          global: 'ReactDOM'
        }
      ]
    })

使用 SplitChunksPlugin分离react和react-dom

    optimization: {
        splitChunks: {
          cacheGroups: {
            commons: {
              name: 'vendors', // 提取出来的技术包的名字
              test: /(react | react - dom)/, // 匹配出需要分离的包
              chunks: 'all'
            }
          }
        }
    },

new HtmlWebpackPlugin对象参数中加入 chunks: ['vendors', pageName],

使用 SplitChunksPlugin分离页面公共文件

    optimization: {
        splitChunks: {
         minSize: 300, // 分离的包的体积的大小,设置成0kb只要引用了,就会打包,假如为1000kb
         cacheGroups: {
            commons: {
             name: 'commons', // 提取出来的包的名字,记得在new HtmlWebpackPlugin中加入chunks: ['commons', pageName],
             chunks: 'all', // 将所有引入的库进行分离;默认是async是将异步引入的库进行分离;inital是将同步引入的库进行分离
             minChunks: 2 // 设置最小引用次数为2次,才会打包出commons.js文件来
            }
         }
        }
    },

new HtmlWebpackPlugin对象参数中加入 chunks: ['commons', pageName],