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 文件

'use strict';

const path = require('path');

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

}

同时,在项目根目录下,创建src文件夹及其子文件helloworld.jsindex.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’ }

  2. 多入口: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'
     }
    
  2. 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],