從零開始的 webpack4 + React 構建

前提條件

安裝 node.js 當前 node.js 版本 :v12.13.1 當前 npm 版本 : 6.12.1javascript

本文從零開始搭建 webpack ,只須要按照步驟一步一步走,最後就可搭建成功 ,請放心食用,無毒css

1、 簡易打包

1.初始化項目 & 建立項目

mkdir webpack4-react && cd webpack4-react
npm init -y
複製代碼

2.安裝 webpack & webpack 的 cli

當前 webpack 版本:4.41.5 當前 webpack-cli 版本:3.3.10html

npm install --save-dev webpack webpack-cli
複製代碼

java

yarn add webpack webpack-cli --dev
複製代碼

調整 package.json 文件,以便確保咱們安裝包是私有的(private),而且移除 main 入口。這能夠防止意外發布你的代碼。node

package.jsonreact

{
  ...
  "description": "webpack4-react",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ...
}

複製代碼

3.下載 lodash 依賴

npm install --save lodash
複製代碼

webpack

yarn add lodash
複製代碼

4.建立如下目錄結構、文件和內容:

webpack4-react
|- package.json
|- /dist
  |- index.html
|- /src
  |- index.js
複製代碼

package.jsongit

{
  "name": "webpack4-react",
  "version": "1.0.0",
  "description": "webpack4-react",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "lodash": "^4.17.15"
  },
  "devDependencies": {
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10"
  }
}
複製代碼

dist/index.htmles6

<!DOCTYPE html>
<html>
  <head>
    <title>webpack4-react</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>
複製代碼

src/index.jsgithub

import _ from 'lodash';
function component() {
  var element = document.createElement('div');
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());
複製代碼

5. 執行打包命令

npx webpack 將看到如下輸出:

Hash: 17a14a12467064d9d4dd
Version: webpack 4.41.5
Time: 1239ms
Built at: 2020-01-04 10:56:16
  Asset      Size  Chunks             Chunk Names
main.js  72.1 KiB       0  [emitted]  main
Entrypoint main = main.js
[1] ./src/index.js 210 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
    + 1 hidden module
複製代碼

此時在 dist 文件夾下已經生成一個 main.js 文件 在瀏覽器中打開 dist 下的 index.html,若是一切訪問都正常,你應該能看到如下文本:'Hello webpack'。

簡易打包已經完成

2、使用配置文件打包

1. 添加 webpack.config.js 配置文件

webpack4-react
|- package.json
|- webpack.config.js
|- /dist
  |- index.html
|- /src
  |- index.js
複製代碼

webpack.config.js

const path = require('path');

module.exports = {
  entry: {
    //配置頁面入口
    index: ['./src/index.js'],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
複製代碼

dist/index.html

...
<body>
  <script src="bundle.js"></script>
</body>
...
複製代碼

2. 添加 NPM 腳本

package.json

{
  "name": "webpack4-react",
  "version": "1.0.0",
  "description": "webpack4-react",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "lodash": "^4.17.15"
  },
  "devDependencies": {
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10"
  }
}
複製代碼

3.執行腳本命令打包

npm run build
複製代碼

終端將輸出:

Hash: 9cbb2fac6cc224bfe661
Version: webpack 4.41.5
Time: 1272ms
Built at: 2020-01-04 11:39:26
  Asset      Size  Chunks             Chunk Names
main.js  72.1 KiB       0  [emitted]  main
Entrypoint main = main.js
[1] ./src/index.js 213 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
    + 1 hidden module
複製代碼

一樣的, dist 文件夾下生成 bundle.js 文件

這樣就實現了基本的 webpack 構建了

3、集成 React

1. 下載 react 和 react-dom

npm install --save-dev react react-dom

2. 下載 babel(編譯 js、jsx,es6 等)

npm install --save-dev @babel/cli @babel/core @babel/preset-react @babel/preset-env @babel/plugin-transform-runtime babel-loader

3. 修改 入口文件

src/index.js

import React from 'react';
import ReactDom from 'react-dom';

const hello = 'Hello React'
ReactDom.render(
	<div>
		<div>{hello}</div>
	</div>,
	document.getElementById('app'),
);
複製代碼

4. 添加 react 根元素

dist/index.html

...
<body>
  <div id="app"></div>
  <script src="bundle.js"></script>
</body>
...
複製代碼

5. 添加 babel 相關配置

爲了使用 babel 解析 jsx

    1. webpack 配置文件中

    webpack.config.js

    ...
    entry: {
      //配置頁面入口
      index: ['./src/index.js'],
    },
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: [
            {
              loader: 'babel-loader',
              options: {
                presets: [
                  [
                    '@babel/preset-env',
                    {
                      useBuiltIns: 'usage',
                      corejs: 3,
                      targets: {
                        chrome: '58',
                        ie: '8',
                      },
                    },
                  ],
                  '@babel/preset-react',
                ],
              },
            },
          ],
        },
      ],
    }
    ...
    複製代碼
    1. 添加 babel 配置文件

    在根目錄下新建 .babelrc 文件

    .babelrc

    {
      "presets": [
        [
          "@babel/preset-env",
          {
            "useBuiltIns": "usage",
            "corejs": 3,
            "targets": {
              "chrome": "58",
              "ie": "8"
            }
          }
        ],
        "@babel/preset-react"
      ],
      "plugins": [
        [
          "@babel/plugin-transform-runtime",
          {
            "absoluteRuntime": false,
            "corejs": false,
            "helpers": true,
            "regenerator": true,
            "useESModules": false
          }
        ]
      ]
    }
    複製代碼

    當前文件目錄結構:

    webpack4-react
    |- /dist
      |- index.html
    |- /src
      |- index.js
    |- .babelrc
    |- package.json
    |- webpack.config.js
    複製代碼

6. 打包

執行 npm run build
終端輸出:
```
$ webpack
Hash: f4d46dd4732764195f93
Version: webpack 4.41.5
Time: 446ms
Built at: 2020-01-04 13:28:48
    Asset     Size  Chunks             Chunk Names
bundle.js  128 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[3] ./src/index.js 211 bytes {0} [built]
    + 7 hidden modules
```
複製代碼

在瀏覽器中打開 dist 下的 index.html,若是一切訪問都正常,你應該能看到如下文本:'Hello React'。

4、創建開發環境

文件結構

webpack4-react
|- /src
  |- index.js
  |- index.html
|- .babelrc
|- package.json
|- webpack.config.js
複製代碼

src/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>webpack4-react</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
複製代碼

1. webpack-dev-server

    1. 下載依賴
    npm install --save-dev webpack-dev-server
    複製代碼
    1. webpack 配置文件中配置 webpack-dev-server webpack.config.js
    ...
    entry: {
      //配置頁面入口
      index: ['./src/index.js'],
    },
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    devServer: {
      contentBase: '/src',
      hot: true,
    },
    ...
    複製代碼

2. html-webpack-plugin

    1. 下載依賴
    npm install --save-dev html-webpack-plugin
    複製代碼
    1. webpack 配置文件中配置 webpack-dev-server webpack.config.js
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    ...
    devServer: {
      contentBase: '/src',
      hot: true,
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html',
        filename: './index.html',
        chunks: ['index'],
        inject: 'body',
      }),
    ],
    ...
    複製代碼

3. 添加 NPM 腳本

package.json

{
  "name": "webpack4-react",
  "version": "1.0.0",
  "description": "webpack4-react",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --config webpack.config.js",
    "build": "webpack --config webpack.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "lodash": "^4.17.15",
    "react": "^16.12.0",
    "react-dom": "^16.12.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.7.7",
    "@babel/core": "^7.7.7",
    "@babel/plugin-transform-runtime": "^7.7.6",
    "@babel/preset-env": "^7.7.7",
    "@babel/preset-react": "^7.7.4",
    "babel-loader": "^8.0.6",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.1"
  }
}
複製代碼

4.執行腳本命令 npm run dev

執行 npm run dev 後會自動打開瀏覽器,此時修改 index.js 文件中內容,瀏覽器會實時更新

刪除 dist 文件夾

執行 npm run build 打包依舊會在 dist 下生成打包文件

5、資源管理

1. 加載 CSS

爲了從 JavaScript 模塊中 import 一個 CSS 文件,你須要在 module 配置中 安裝並添加 style-loader 和 css-loader:

    1. 下載 style-loader css-loader
    npm install --save-dev style-loader css-loader
    複製代碼
    1. webpack.config.js 中配置 css 的 loader
    module: {
          rules: [
            {
              test: /\.css$/,
              use: [
              'style-loader',
              'css-loader',
              ]
            },
      ...
      }
    複製代碼
    1. src/index.js 中引入 css src 下新建 style/reset.css style/reset.css
    * {
      padding: 0;
      margin: 0;
    }
    div {
      font-size: 20px;
    }
    複製代碼
    src/index.js
    import './style/reset.css';
    複製代碼
    執行 npm run dev ,會看到 reset.css 中的樣式已經生效

2. CSS 預處理器 & 模塊化 & 兼容性處理

    1. 下載依賴
    npm install --save-dev autoprefixer postcss-loader
    npm install --save-dev less-loader node-sass sass sass-loader
    複製代碼

    這個過程當中安裝 node-sass 可能會很慢, 耐心等待

    1. 建立 React 組件

    建立以下目錄文件及內容:

    webpack4-react
    |- src
      |- components
        |- Date
          |- index.jsx
          |- style.scss
      |- style
        |- reset.scss
      |- index.js
    |- .babelrc
    |- package.json
    |- webpack.config.js
    複製代碼

    src/components/Date/index.jsx

    import React from 'react';
    import style from './style.scss';
    
    class DateComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          date: new Date(),
        };
      }
    
      componentDidMount() {
        this.timerID = setInterval(() => this.tick(), 1000);
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date(),
        });
      }
    
      render() {
        const { date } = this.state;
        return (
         <div>
            <div className={style.title}>時間</div>
            <div className={style.title}>
            {date.toLocaleTimeString()}
            </div>
          </div>
        );
      }
    }
    export default DateComponent;
    複製代碼

    src/components/Date/style.scss

    .title {
      height: 50px;
      font: bold 20px '微軟雅黑';
      text-align: center;
      color: #000;
    }
    複製代碼
    1. 引入組件

    src/index.js

    import React from 'react';
    import ReactDom from 'react-dom';
    import DateComponents from './components/Date/index.jsx';
    import './style/reset.scss';
    
    const hello = 'Hello React';
    ReactDom.render(
      <div>
        <div>{hello}</div>
        <DateComponents />
      </div>,
      document.getElementById('app')
    );
    複製代碼
    1. 新增 CSS 相關的 webpack 配置 根目錄下新建 tools/utils.js
    // css 配置
    const styleLoader = {
      loader: 'style-loader',
    };
    const cssLoader = {
      loader: 'css-loader',
      options: {
        modules: true, // webpack3 爲 module
        sourceMap: true,
        importLoaders: 2,
      },
    };
    const postCssLoader = {
      loader: 'postcss-loader',
    };
    const sassLoader = {
      loader: 'sass-loader',
      options: {
        sourceMap: true,
      },
    };
    const lessLoader = {
      loader: 'less-loader',
    };
    exports.loadersConfig = {
      styleLoader,
      cssLoader,
      postCssLoader,
      sassLoader,
      lessLoader,
    };
    // css 配置
    複製代碼

    webpack.config.js

    ...
    const utils = require('./tools/utils.js');
    const {
      postCssLoader,
      styleLoader,
      sassLoader,
      cssLoader,
    } = utils.loadersConfig;
    ...
    module.exports = {
      ...
      module: {
        rules: [
          {
            test: /\.css$/,
            exclude: /node_modules/,
            use: [styleLoader, cssLoader, postCssLoader],
          },
          {
            test: /\.scss$/,
            include: [/pages/, /components/, /style/],
            use: [
              styleLoader,
              cssLoader,
              postCssLoader,
              sassLoader,
            ],
          },
        }
      ...
    };
    複製代碼
    1. 新增 postcss-loader 配置文件 根目錄下新增 postcss.config.js
    const AUTOPREFIXER_BROWSERS = [
      'Android 2.3',
      'Android >= 4',
      'Chrome >= 35',
      'Firefox >= 31',
      'Explorer >= 8',
      'iOS >= 7',
      'Opera >= 12',
      'Safari >= 7.1',
    ];
    module.exports = {
      plugins: [require('autoprefixer')({overrideBrowserslist: ['> 0.15% in CN']})],
    };
    複製代碼

這時候執行 npm run dev 命令會報錯,由於缺乏一些 babel 依賴,下載一下就行了

npm install --save @babel/runtime core-js
複製代碼

執行 npm run dev ,自動打開瀏覽器,css 相關的配置構建完成

3. 圖片處理

    1. 下載依賴
    npm install --save-dev file-loader url-loader
    複製代碼
    1. webpack 配置中添加規則
    ...
    module: {
      rules: [
          ...
          {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  name: '[path][name].[ext]',
                  limit: 1024 * 15,
                  fallback: 'file-loader',
                },
              },
            ],
          },
          ...
      ]
    }
    ...
    複製代碼
    1. React 組件中 引入圖片 src/components/Date/index.jsx
    ...
    import reactLogo from './../../images/React.svg';
    import webpackLogo from './../../images/webpack.svg';
    ...
    render() {
      const { date } = this.state;
      return (
        <div>
          <div className={style.title}>時間</div>
          <div>
          <img className={style.logo} src={reactLogo} alt="" />
          <img className={style.logo} src={webpackLogo} alt="" />
          </div>
          <div className={style.title}>
          {date.toLocaleTimeString()}
          </div>
        </div>
      );
    }
    ...
    複製代碼

4. 其餘

字體、數據等參考 webpack 官網 資源管理

6、 resolve 配置

在代碼引入組件或圖片時,咱們來配置一些便捷的方式

1. 配置

webpack.config.js

// 引入 node 的 path 模塊
const path = require('path');
...
module.exports = {
  ...
  resolve: {
    // 設置模塊導入規則,import/require時會直接在這些目錄找文件
    modules: ['node_modules'],
    // import導入時省略後綴
    extensions: ['.js', '.jsx', '.scss', '.less', '.css', '.json'],
    // import導入時別名
    alias: {
      '@components': path.resolve('./src/components'),
      '@images': path.resolve('./src/images'),
      '@style': path.resolve('./src/style'),
    },
  },
  ...
}

複製代碼

2. 使用

舉個 🌰

src/index.js 中

import React from 'react';
import ReactDom from 'react-dom';
import DateComponents from '@components/Date/index.jsx';
import '@style/reset.scss';

const hello = 'Hello React';
ReactDom.render(
  <div>
    <div>{hello}</div>
    <DateComponents />
  </div>,
  document.getElementById('app')
);

複製代碼

此時 執行 npm run dev 查看

7、 環境配置構建

開發環境(development)和生產環境(production)的構建目標差別很大。在開發環境中,咱們須要具備強大的、具備實時從新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,咱們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。因爲要遵循邏輯分離,咱們一般建議爲每一個環境編寫彼此獨立的 webpack 配置。

1. 使用 webpack-merge 配置

    1. 下載依賴
    npm install --save-dev webpack-merge clean-webpack-plugin uglifyjs-webpack-plugin
    複製代碼
    1. 拆分 webpack 配置

    根目錄下建立 webpack 文件夾

    |- webpack
      |- webpack.common.js
      |- webpack.dev.js
      |- webpack.production.js
    複製代碼

    webpack.common.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    const utils = require('./../tools/utils');
    const { postCssLoader, styleLoader, sassLoader, cssLoader } = utils.loadersConfig;
    
    module.exports = {
      entry: {
        //配置頁面入口
        index: ['./src/index.js'],
      },
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, '../dist'),
      },
      devServer: {
        contentBase: '/src',
        hot: true,
      },
      resolve: {
        // 設置模塊導入規則,import/require時會直接在這些目錄找文件
        modules: ['node_modules'],
        // import導入時省略後綴
        extensions: ['.js', '.jsx', '.scss', '.less', '.css', '.json'],
        // import導入時別名
        alias: {
        '@assets': path.resolve('./src/assets'),
        '@common': path.resolve('./src/common'),
        '@components': path.resolve('./src/components'),
        '@images': path.resolve('./src/images'),
        '@pages': path.resolve('./src/pages'),
        '@style': path.resolve('./src/style'),
        },
      },
      plugins: [
        new HtmlWebpackPlugin({
        template: './src/index.html',
        filename: './index.html',
        chunks: ['index'],
        inject: 'body',
        }),
      ],
      module: {
        rules: [
          {
            test: /\.css$/,
            exclude: /node_modules/,
            use: [styleLoader, cssLoader, postCssLoader],
          },
          {
            test: /\.scss$/,
            include: [/pages/, /components/, /style/],
            use: [styleLoader, cssLoader, postCssLoader, sassLoader],
          },
          {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  name: '[path][name].[ext]',
                  limit: 1024 * 15,
                  fallback: 'file-loader',
                },
              },
            ],
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                          useBuiltIns: 'usage',
                          corejs: 3,
                            targets: {
                            chrome: '58',
                            ie: '8',
                          },
                      },
                    ],
                    '@babel/preset-react',
                  ],
                },
              },
            ],
          },
        ],
      },
    };
    複製代碼

    webpack.dev.js

    const merge = require('webpack-merge');
    const common = require('./webpack.common.js');
    module.exports = merge(common, {
      mode: 'development',
      devtool: 'inline-source-map',
      devServer: {
        contentBase: '/src',
        hot: true,
      }
    });
    複製代碼

    webpack.production.js

    const merge = require('webpack-merge');
    const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); // 用來縮小(壓縮優化)js文件
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    const common = require('./webpack.common.js');
    module.exports = merge(common, {
      mode: 'production',
      devtool: 'source-map',
      plugins: [
        new UglifyJSPlugin({
          sourceMap: true,
        }),
        new CleanWebpackPlugin(),
      ],
    });
    複製代碼
    1. npm 腳本命令更改 package.json
    "dev": "webpack-dev-server --open --config webpack/webpack.dev.js",
    "build": "webpack --config webpack/webpack.production.js"
    複製代碼
    1. 設置環境變量 下載依賴
    npm install --save-dev cross-env
    複製代碼

    npm 腳本命令更改

    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --config webpack/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --config webpack/webpack.production.js"
    複製代碼

8、 其餘優化

1. 配置中獲取環境變量

在 npm 腳本執行的時候設置的環境變量經過 process.env.NODE_ENV 來獲取,process.env.NODE_ENV 的值 在當前腳本下有兩種: development , production , 藉此能夠根據不一樣環境設置不一樣的配置。

2. 添加 html-loader 及 html 優化

    1. 下載依賴
    npm install --save-dev html-loader
    複製代碼
    1. 配置

    在根目錄下添加一個 react.ico 的圖片待用,用於在 HtmlWebpackPlugin 中配置網頁的 ico 圖片

    webpack.config.common.js

    ...
    entry: {
      //配置頁面入口
      index: ['./src/index.js'],
    },
    output: {
      //配置輸出選項
      path: path.resolve(__dirname, '../dist'), //輸出路徑爲,當前路徑下
      filename: '[name].[hash:5].js', //輸出後的文件名稱
    },
    ...
    plugins: [
      new HtmlWebpackPlugin({
        title: 'webpack & react',
        template: './src/index.html', //本地模板文件的位置,支持加載器(如handlebars、ejs、undersore、html等),如好比 handlebars!src/index.hbs;
        filename: './index.html', //輸出文件的文件名稱,默認爲index.html,不配置就是該文件名;此外,還能夠爲輸出文件指定目錄位置(例如'html/index.html')
        chunks: ['index'], // chunks主要用於多入口文件,當你有多個入口文件,那就回編譯後生成多個打包後的文件,那麼chunks 就能選擇你要使用那些js文件
        inject: 'body', //一、true或者body:全部JavaScript資源插入到body元素的底部二、head: 全部JavaScript資源插入到head元素中三、false: 全部靜態資源css和JavaScript都不會注入到模板文件中
        showErrors: true, //是否將錯誤信息輸出到html頁面中
        hash: false, //是否爲全部注入的靜態資源添加webpack每次編譯產生的惟一hash值
        favicon: 'react.ico', //添加特定的 favicon 路徑到輸出的 HTML 文件中。
        minify: {
          //是否對大小寫敏感,默認false
          caseSensitive: true,
          //是否簡寫boolean格式的屬性如:disabled="disabled" 簡寫爲disabled  默認false
          collapseBooleanAttributes: true,
          //是否去除空格,默認false
          collapseWhitespace: true,
          //是否壓縮html裏的css(使用clean-css進行的壓縮) 默認值false;
          minifyCSS: true,
          //是否壓縮html裏的js(使用uglify-js進行的壓縮)
          minifyJS: true,
          //Prevents the escaping of the values of attributes
          preventAttributesEscaping: true,
          //是否移除屬性的引號 默認false
          removeAttributeQuotes: true,
          //是否移除註釋 默認false
          removeComments: true,
          //從腳本和樣式刪除的註釋 默認false
          removeCommentsFromCDATA: true,
          //是否刪除空屬性,默認false
          removeEmptyAttributes: true,
          //  若開啓此項,生成的html中沒有 body 和 head,html也未閉合
          removeOptionalTags: false,
          //刪除多餘的屬性
          removeRedundantAttributes: true,
          //刪除script的類型屬性,在h5下面script的type默認值:text/javascript 默認值false
          removeScriptTypeAttributes: true,
          //刪除style的類型屬性, type="text/css" 同上
          removeStyleLinkTypeAttributes: true,
          //使用短的文檔類型,默認false
          useShortDoctype: true,
        },
    }),
    ]
    ...
    module: {
      rules: [
        {
          test: /\.html$/,
          use: 'html-loader',
        },
      ]
    }
    複製代碼

3. 壓縮 提取 CSS

    1. 下載依賴
    npm install --save-dev mini-css-extract-plugin
    複製代碼
    1. 在生產環境中壓縮 CSS, 開發環境中不壓縮 scss

    webpack.config.common.js 其中 關於 .scss$ 的 rules 替換下

    ...
    const devMode = process.env.NODE_ENV !== 'production';
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    ...
    module.exports = {
      ...
      plugins: [
        ...
        new MiniCssExtractPlugin({
          filename: devMode ? '[name].css' : '[name]_[hash:5].css',
          chunkFilename: devMode ? '[id].css' : '[id]_[hash:5].css',
          disable: false, //是否禁用此插件
          allChunks: true,
        }),
        ...
      ]
      ...
      module: {
        rules: [
          {
            test: /\.html$/,
            use: "html-loader"
          },
          {
            test: /\.css$/,
            exclude: /node_modules/,
            use: [styleLoader, cssLoader, postCssLoader]
          },
          {
            test: /\.scss$/,
            include: [/pages/, /components/, /style/],
            use: [
              devMode ? styleLoader : MiniCssExtractPlugin.loader,
              cssLoader,
              postCssLoader,
              sassLoader,
            ],
          },
        ],
      }
    複製代碼
    1. 再次執行 npm run build 會發如今 dist 文件夾裏多了些 css,css.map 文件

4. 生產環境壓縮 JS, 打包時清除 dist 文件夾

    1. 下載依賴
    npm install --save-dev uglifyjs-webpack-plugin clean-webpack-plugin
    複製代碼
    1. webpack 配置

    webpack.production.js

    ...
    const merge = require('webpack-merge');
    const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    const common = require('./webpack.config.common.js');
    module.exports = merge(common, {
      mode: 'production',
      devtool: 'source-map',
      plugins: [
        new UglifyJSPlugin({
          sourceMap: true,
        }),
        new CleanWebpackPlugin(),
      ],
    });
    ...
    複製代碼

5. happypack 加快打包速度

    1. 下載依賴
    npm install --save-dev happypack
    複製代碼
    1. 配置

    webpack.config.common.js

    ...
    const os = require('os');
    const HappyPack = require('happypack');
    const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
    ...
    plugins: [
      ...
      new HappyPack({
        id: 'babel', //用id來標識 happypack處理那裏類文件
        threadPool: happyThreadPool, //共享進程池
        loaders: [
          {
            loader: 'babel-loader',
          },
        ],
      }),
      ...
    ],
    ...
    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          use: ['happypack/loader?id=babel'],
          exclude: /node_modules/, //設置node_modules裏的js文件不用解析
        },
      ]
    }
    ...
    複製代碼

5. polyfill 編譯 es6 的新語法

    1. 下載依賴
    npm install --save-dev @babel/polyfill @babel/plugin-transform-arrow-functions @babel/preset-es2017
    複製代碼
    1. 配置

    webpack.common.js

    entry: {
      //配置頁面入口
      index: ['@babel/polyfill', './src/index.js'],
    },
    複製代碼
    1. 測試語法支持

    src/index.js

    async function f() {
      return 'hello world';
    }
    function* helloWorldGenerator() {
      yield 'hello';
      yield 'world';
      return 'ending';
    }
    const hw = helloWorldGenerator();
    console.log('Generator>>>>>>', hw.next());
    const arr = [1, 2, 3, 4, 5, 1, 2, 3, 5];
    const setArr = new Set(arr);
    console.log('setArr?>>>>>>', setArr);
    const m = new Map();
    console.log('Map>>>>>>>>', m);
    f().then(v => console.log('async>>>>', v));
    // IE 不支持 Symbol
    const helloSymbol = Symbol('www');
    console.log('Symbol>>>>>>', helloSymbol);
    console.log('flat>>>>>>', [1, [2, [3]]].flat(Infinity));
    
    console.log('---------------');
    console.log('Promise');
    new Promise(resolve => {
      setTimeout(() => {
        resolve('hello');
      }, 2000);
    }).then(value => {
      console.log(value);
      return new Promise(resolve => {
        setTimeout(() => {
          resolve('world');
        }, 2000);
      });
    }).then(value => {
      console.log(`${value} world`);
    });
    console.log('---------------');
    
    const target = {};
    const handler = {};
    const proxy = new Proxy(target, handler);
    proxy.a = 'b';
    console.log('proxy>>>>>', target.a);
    // 不支持
    // class A {
    // 	static name = 'name';
    // }
    // console.log('static class>>>>>', new A());
    複製代碼

    打包 npm run build , 把 dist 文件的 index.html 用 IE 打開驗證

9、 代碼規範- eslint & stylelint

1. 添加編輯器配置文件以及插件

vs code 格式化插件 使用的是 Prettier - Code formatter 以及 ESLint

|- .vscode
	|- setting.json
複製代碼

setting.json

{
  "editor.tabSize": 4,
  "prettier.singleQuote": true,
  "editor.detectIndentation": false,
  "editor.renderControlCharacters": true,
  "editor.renderWhitespace": "all",
  "emmet.includeLanguages": {
    "javascript": "javascriptreact"
  },
  "prettier.trailingComma": "es5",
  "emmet.triggerExpansionOnTab": true,
  "javascript.implicitProjectConfig.experimentalDecorators": true,
  "workbench.colorTheme": "Solarized Light",
  "window.zoomLevel": 0,
  "prettier.useTabs": true,
  "editor.foldingStrategy": "indentation",
  "explorer.confirmDelete": false,
  "javascript.updateImportsOnFileMove.enabled": "never",
  "eslint.validate": [
    {
      "language": "javascript",
      "autoFix": true
    },
    {
      "language": "javascriptreact",
      "autoFix": true
    }
  ],
  "eslint.autoFixOnSave": true
}
複製代碼

2. eslint

    1. 下載依賴
    npm i babel-eslint eslint eslint-config-airbnb eslint-config-react-app eslint-friendly-formatter eslint-loader eslint-plugin-flowtype eslint-plugin-html eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react autoprefixer -D
    複製代碼
    1. webpack 的 eslint 配置

    根目錄下新建 .eslintrc.js 文件

    module.exports = {
      root: true,
      env: {
        browser: true,
        commonjs: true,
        es6: true,
      },
      extends: [
        'airbnb',
      ],
      globals: {
        $: true,
        process: true,
        __dirname: true,
      },
      parser: 'babel-eslint',
      parserOptions: {
        //es6的module模式
        sourceType: 'module',
        ecmaFeatures: {
          experimentalObjectRestSpread: true,
          jsx: true,
        },
        ecmaVersion: 9,
      },
      settings: {
        'import/ignore': ['node_modules', '.s?css', '@w*'],
      },
      // "excludedFiles": "*.test.js",
      plugins: ['react', 'import', 'jsx-a11y'],
      rules: {
        'import/no-unresolved': 0,
        'import/extensions': 0,
        'import/prefer-default-export': 0,
    
        'react/prop-types': 0,
        'react/jsx-filename-extension': 0,
        'react/prefer-stateless-function': 0,
        'react/jsx-indent': [2, 'tab'],
        'react/jsx-indent-props': [2, 'tab'],
        'react/require-default-props': 0,
        // // @off 同構應用須要在 didMount 裏寫 setState
        'react/no-did-mount-set-state': 0,
    
        'jsx-a11y/anchor-is-valid': 0,
        'jsx-a11y/click-events-have-key-events': 0,
        'jsx-a11y/mouse-events-have-key-events': 0,
        'jsx-a11y/no-noninteractive-element-interactions': 0,
        'jsx-a11y/no-static-element-interactions': 0,
    
        'no-return-assign': 0,
        'no-console': 0,
        // 0、一、2分別表示不開啓檢查、警告、錯誤
        indent: [2, 'tab', { SwitchCase: 1 }], // tab縮進
        // 圈複雜度
        complexity: [2, 9],
        'max-params': [2, 7],
        'max-depth': [2, 4],
        'max-len': [
          'error',
          {
            code: 150,
            tabWidth: 4,
            ignoreComments: true,
            ignoreUrls: true,
            ignoreStrings: true,
            ignoreTemplateLiterals: true,
            ignoreRegExpLiterals: true,
          },
        ],
        'no-tabs': 0,
        'object-curly-newline': [
          0,
          {
            ObjectExpression: 'always',
            ObjectPattern: { multiline: true },
            ImportDeclaration: 'never',
            ExportDeclaration: {
              multiline: true,
            },
          },
        ],
        'object-curly-spacing': 0,
    
        'arrow-parens': [2, 'as-needed'],
        // 最大回調層數
        'max-nested-callbacks': [2, 3],
        'no-unused-vars': [
          2,
          {
            argsIgnorePattern: '^React',
            varsIgnorePattern: '[Rr]eact|[Ss]tyle',
          },
        ],
        'no-extra-boolean-cast': 0,
        'array-callback-return': 0,
        'no-param-reassign': 0,
        'jsx-quotes': [0, 'prefer-double'], //強制在JSX屬性(jsx-quotes)中一導致用雙引號
        'no-underscore-dangle': 0,
        'quote-props': 0,
        // "no-native-reassign": 2,//不能重寫native對象
        // // if while function 後面的{必須與if在同一行,java風格。
        // "brace-style": [2, "1tbs", { "allowSingleLine": true }],
        // // 雙峯駝命名格式
        // "camelcase": 2,
        // // 以方括號取對象屬性時,[ 後面和 ] 前面是否須要空格, 可選參數 never, always
        // "computed-property-spacing": [2,"never"],
        // //容許箭頭函數能夠省略小括號
        // 'arrow-parens': 0,
        // 'no-extra-semi': 2, // 不容許多餘的分號
        // //容許使用async-await函數
        // 'generator-star-spacing': 0,
        // //在開發環境開啓debugger功能,生產環境禁止使用debugger
        // 'no-debugger': process.env.NODE_ENV === 'development' ? 0 : 2,
        // "quotes": [2, "single"], //單引號
        // "no-var": 2, //對var警告
        // "semi": ["error", "always"], //不強制使用分號
        // "no-irregular-whitespace": 0, //不規則的空白不容許
        // "no-alert": 2, //禁止使用alert confirm prompt
        // "no-lone-blocks": 0, //禁止沒必要要的嵌套塊
        // "no-class-assign": 2, //禁止給類賦值
        // "no-cond-assign": 2, //禁止在條件表達式中使用賦值語句
        // "no-const-assign": 2, //禁止修改const聲明的變量
        // "no-delete-var": 2, //不能對var聲明的變量使用delete操做符
        // "no-dupe-keys": 2, //在建立對象字面量時不容許鍵重複
        // "no-duplicate-case": 2, //switch中的case標籤不能重複
        // "no-dupe-args": 2, //函數參數不能重複
        // "no-empty": 2, //塊語句中的內容不能爲空
        // "no-func-assign": 2, //禁止重複的函數聲明
        // "no-invalid-this": 0, //禁止無效的this,只能用在構造器,類,對象字面量
        // "no-redeclare": 2, //禁止重複聲明變量
        // "no-spaced-func": 2, //函數調用時 函數名與()之間不能有空格
        // "no-this-before-super": 0, //在調用super()以前不能使用this或super
        // "no-undef": 2, //不能有未定義的變量
        // "no-use-before-define": 2, //未定義前不能使用
        // // "camelcase": 0, //強制駝峯法命名
        // "no-mixed-spaces-and-tabs": 0, //禁止混用tab和空格
        // "prefer-arrow-callback": 0, //比較喜歡箭頭回調
        // "arrow-spacing": 0, //=>的前/後括號
        //
        // // 禁止在 componentDidMount 裏面使用 setState
    
        // // 禁止在 componentDidUpdate 裏面使用 setState
        // 'react/no-did-update-set-state': 2,
        // // 禁止拼寫錯誤
    
        // 'react/no-typos': 2,
        // // 禁止使用字符串 ref
        // 'react/no-string-refs': 2,
        // // @fixable 禁止出現 HTML 中的屬性,如 class
        // 'react/no-unknown-property': 2,
        // // 禁止出現未使用的 propTypes
        // // @off 不強制要求寫 propTypes
        // 'react/no-unused-prop-types': 2,
        // // 出現 jsx 的地方必須 import React
        // // @off 已經在 no-undef 中限制了
        // 'react/react-in-jsx-scope': 0,
        // // 非 required 的 prop 必須有 defaultProps
        // // @off 不強制要求寫 propTypes
        // 'react/require-default-props': 0,
        // // render 方法中必須有返回值
        // 'react/require-render-return': 2,
        // // @fixable 組件內沒有 children 時,必須使用自閉和寫法
        // // @off 不必限制
        // 'react/self-closing-comp': 0,
        // // style 屬性的取值必須是 object
        // 'react/style-prop-object': 2,
        // // HTML 中的自閉和標籤禁止有 children
        // 'react/void-dom-elements-no-children': 2,
        // // 數組中的 jsx 必須有 key
        // 'react/jsx-key': 2,
        // // 禁止在 jsx 中使用像註釋的字符串
        // 'react/jsx-no-comment-textnodes': 2,
        // // 禁止出現重複的 props
        // 'react/jsx-no-duplicate-props': 2,
        // // 禁止使用未定義的 jsx elemet
        // 'react/jsx-no-undef': 2,
        // // jsx 文件必須 import React
        // 'react/jsx-uses-react': 2,
        // // 定義了的 jsx element 必須使用
        // 'react/jsx-uses-vars': 2,
        // // @fixable 多行的 jsx 必須有括號包起來
        // // @off 不必限制
        // 'react/jsx-wrap-multilines': 2,
        // "react/no-array-index-key": 2, // 遍歷出來的節點必須加key
        // "react/no-children-prop": 2, // 禁止使用children做爲prop
        // "react/no-direct-mutation-state": 2, // 禁止直接this.state = 方式修改state 必須使用setState
      },
    };
    複製代碼

    webpack.common.js

    ...
    module: {
      rules: [
        ...
        {
          test: /\.(js|jsx)$/,
          loader: 'eslint-loader',
          enforce: 'pre',
          include: [path.resolve(__dirname, 'src')], // 指定檢查的目錄
          options: {
            // 這裏的配置項參數將會被傳遞到 eslint 的 CLIEngine
            formatter: require('eslint-friendly-formatter'), // 指定錯誤報告的格式規範
          },
        },
      ]
    }
    ...
    複製代碼

    根目錄下新建 .eslintignore 文件 用來制定忽略某些文件的 eslint 校驗

    webpack
    複製代碼

3. stylelint

    1. 下載依賴
    npm i stylelint stylelint-config-recommended stylelint-config-standard stylelint-order stylelint-webpack-plugin -D
    複製代碼
    1. stylelint 配置

    webpack.dev.js

    const merge = require("webpack-merge");
    const StyleLintPlugin = require("stylelint-webpack-plugin");
    const common = require("./webpack.common.js");
    module.exports = merge(common, {
      mode: "development",
      devtool: "inline-source-map",
      devServer: {
        contentBase: "/src",
        hot: true
      },
      plugins: [
        new StyleLintPlugin({
          fix: true,
          files: ["src/**/*.scss"],
          failOnError: false,
          quiet: true,
          syntax: "scss",
          cache: true
        })
      ]
    });
    複製代碼

    根目錄下新建 .stylelintrc.js 文件

    module.exports = {
      extends: ['stylelint-config-standard', 'stylelint-config-recommended'],
      plugins: ['stylelint-order'],
      rules: {
        'order/order': [
          // "at-rules",
          // "declarations",
          'custom-properties',
          'dollar-variables',
          'rules',
        ],
        'order/properties-order': [
          'position',
          'z-index',
          'top',
          'bottom',
          'left',
          'right',
          'float',
          'clear',
          'columns',
          'columns-width',
          'columns-count',
          'column-rule',
          'column-rule-width',
          'column-rule-style',
          'column-rule-color',
          'column-fill',
          'column-span',
          'column-gap',
          'display',
          'grid',
          'grid-template-rows',
          'grid-template-columns',
          'grid-template-areas',
          'grid-auto-rows',
          'grid-auto-columns',
          'grid-auto-flow',
          'grid-column-gap',
          'grid-row-gap',
          'grid-template',
          'grid-template-rows',
          'grid-template-columns',
          'grid-template-areas',
          'grid-gap',
          'grid-row-gap',
          'grid-column-gap',
          'grid-area',
          'grid-row-start',
          'grid-row-end',
          'grid-column-start',
          'grid-column-end',
          'grid-column',
          'grid-column-start',
          'grid-column-end',
          'grid-row',
          'grid-row-start',
          'grid-row-end',
          'flex',
          'flex-grow',
          'flex-shrink',
          'flex-basis',
          'flex-flow',
          'flex-direction',
          'flex-wrap',
          'justify-content',
          'align-content',
          'align-items',
          'align-self',
          'order',
          'table-layout',
          'empty-cells',
          'caption-side',
          'border-collapse',
          'border-spacing',
          'list-style',
          'list-style-type',
          'list-style-position',
          'list-style-image',
          'ruby-align',
          'ruby-merge',
          'ruby-position',
          'box-sizing',
          'width',
          'min-width',
          'max-width',
          'height',
          'min-height',
          'max-height',
          'padding',
          'padding-top',
          'padding-right',
          'padding-bottom',
          'padding-left',
          'margin',
          'margin-top',
          'margin-right',
          'margin-bottom',
          'margin-left',
          'border',
          'border-width',
          'border-top-width',
          'border-right-width',
          'border-bottom-width',
          'border-left-width',
          'border-style',
          'border-top-style',
          'border-right-style',
          'border-bottom-style',
          'border-left-style',
          'border-color',
          'border-top-color',
          'border-right-color',
          'border-bottom-color',
          'border-left-color',
          'border-image',
          'border-image-source',
          'border-image-slice',
          'border-image-width',
          'border-image-outset',
          'border-image-repeat',
          'border-top',
          'border-top-width',
          'border-top-style',
          'border-top-color',
          'border-top',
          'border-right-width',
          'border-right-style',
          'border-right-color',
          'border-bottom',
          'border-bottom-width',
          'border-bottom-style',
          'border-bottom-color',
          'border-left',
          'border-left-width',
          'border-left-style',
          'border-left-color',
          'border-radius',
          'border-top-right-radius',
          'border-bottom-right-radius',
          'border-bottom-left-radius',
          'border-top-left-radius',
          'outline',
          'outline-width',
          'outline-color',
          'outline-style',
          'outline-offset',
          'overflow',
          'overflow-x',
          'overflow-y',
          'resize',
          'visibility',
          'font',
          'font-style',
          'font-variant',
          'font-weight',
          'font-stretch',
          'font-size',
          'font-family',
          'font-synthesis',
          'font-size-adjust',
          'font-kerning',
          'line-height',
          'text-align',
          'text-align-last',
          'vertical-align',
          'text-overflow',
          'text-justify',
          'text-transform',
          'text-indent',
          'text-emphasis',
          'text-emphasis-style',
          'text-emphasis-color',
          'text-emphasis-position',
          'text-decoration',
          'text-decoration-color',
          'text-decoration-style',
          'text-decoration-line',
          'text-underline-position',
          'text-shadow',
          'white-space',
          'overflow-wrap',
          'word-wrap',
          'word-break',
          'line-break',
          'hyphens',
          'letter-spacing',
          'word-spacing',
          'quotes',
          'tab-size',
          'orphans',
          'writing-mode',
          'text-combine-upright',
          'unicode-bidi',
          'text-orientation',
          'direction',
          'text-rendering',
          'font-feature-settings',
          'font-language-override',
          'image-rendering',
          'image-orientation',
          'image-resolution',
          'shape-image-threshold',
          'shape-outside',
          'shape-margin',
          'color',
          'background',
          'background-image',
          'background-position',
          'background-size',
          'background-repeat',
          'background-origin',
          'background-clip',
          'background-attachment',
          'background-color',
          'background-blend-mode',
          'isolation',
          'clip-path',
          'mask',
          'mask-image',
          'mask-mode',
          'mask-position',
          'mask-size',
          'mask-repeat',
          'mask-origin',
          'mask-clip',
          'mask-composite',
          'mask-type',
          'filter',
          'box-shadow',
          'opacity',
          'transform-style',
          'transform',
          'transform-box',
          'transform-origin',
          'perspective',
          'perspective-origin',
          'backface-visibility',
          'transition',
          'transition-property',
          'transition-duration',
          'transition-timing-function',
          'transition-delay',
          'animation',
          'animation-name',
          'animation-duration',
          'animation-timing-function',
          'animation-delay',
          'animation-iteration-count',
          'animation-direction',
          'animation-fill-mode',
          'animation-play-state',
          'scroll-behavior',
          'scroll-snap-type',
          'scroll-snap-destination',
          'scroll-snap-coordinate',
          'cursor',
          'touch-action',
          'caret-color',
          'ime-mode',
          'object-fit',
          'object-position',
          'content',
          'counter-reset',
          'counter-increment',
          'will-change',
          'pointer-events',
          'all',
          'page-break-before',
          'page-break-after',
          'page-break-inside',
          'widows',
        ],
        indentation: 'tab',
        'color-no-invalid-hex': true,
        'font-family-no-missing-generic-family-keyword': null,
        'font-family-name-quotes': null,
        'function-url-quotes': 'always',
        'at-rule-no-unknown': null,
        'no-eol-whitespace': null,
        'selector-attribute-quotes': 'always',
        'string-quotes': 'single',
        'selector-pseudo-element-colon-notation': null,
        'at-rule-no-vendor-prefix': true,
        'media-feature-name-no-vendor-prefix': null,
        'media-feature-name-no-unknown': null,
        'property-no-vendor-prefix': null,
        'selector-no-vendor-prefix': true,
        'value-no-vendor-prefix': true,
        'selector-pseudo-class-no-unknown': null,
        'shorthand-property-no-redundant-values': null,
        'at-rule-empty-line-before': null,
        'at-rule-name-space-after': null,
        'comment-empty-line-before': null,
        'declaration-bang-space-before': null,
        'declaration-empty-line-before': null,
        'function-comma-newline-after': null,
        'function-name-case': null,
        'function-parentheses-newline-inside': null,
        'function-max-empty-lines': null,
        'function-whitespace-after': null,
        'number-leading-zero': null,
        'number-no-trailing-zeros': null,
        'rule-empty-line-before': null,
        'selector-combinator-space-after': null,
        'selector-list-comma-newline-after': null,
        // "selector-pseudo-element-colon-notation": null,
        'unit-no-unknown': null,
        'no-descending-specificity': null,
        'value-list-max-empty-lines': null,
      },
    };
    複製代碼

10、 webpack DLL

在用 Webpack 打包的時候,對於一些不常常更新的第三方庫,好比 react,lodash,咱們並不但願每次打包都去編譯他們,因此,應該只打包一次,而後屢次使用,因而有了 DLL 的打包

下載依賴:

npm install webpack-bundle-analyzer --save-dev
複製代碼
    1. 新建配置文件

    webpack 文件夾下新建文件 webpack.dll.config.js webpack.dll.config.js

    const webpack = require('webpack');
    const library = '[name]_lib';
    const path = require('path');
    const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
    console.log('process.env.NODE_ENV>>>>', process.env.NODE_ENV)
    module.exports = {
      mode: 'production',
      entry: {
        vendors: [
          'react',
          '@babel/polyfill',
          'react-dom',
          'core-js',
          'classnames'
        ],
      },
      output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, './../ools'),
        library,
      },
      plugins: [
        new webpack.DllPlugin({
          path: path.join(__dirname, './../tools/[name]-manifest.json'),
          name: library,
        }),
        new BundleAnalyzerPlugin(),
      ],
    };
    複製代碼
  • 2 webpack.common.js 中配置
    plugins: [
      new webpack.DllReferencePlugin({
        context: __dirname,
        manifest: require('./tools/vendors-manifest.json'),
      }),
    ]
    複製代碼
    1. 新建 dll 腳本命令
    "scripts": {
      ...
      "dll": "cross-env NODE_ENV=production webpack --config webpack/webpack.dll.config.js",
      ...
    },
    複製代碼

執行 npm run dll 會在 tools 文件夾下生成對應的 dll 文件: vendors-manifest.jsonvendors.dll.js,同時會自動打開瀏覽器查看到對應文件大小

完整源碼

相關文章
相關標籤/搜索