webpack4.x經常使用配置 + webpack4打包多頁面

配套代碼demo: https://github.com/FinGet/web...。博客原文: https://finget.github.io/2019/07/24/webpack4-0/

打包多頁面在git倉庫裏,並無單獨寫出來。javascript

初始化:css

yarn init -y
yarn add webpack webpack-cli -Dhtml

webpack-cli的做用就是讓咱們能在命令行中使用 webpacknpx webpakck 這些指令。

webpack基礎配置

// webpack 是node寫出來,因此要按node的寫法
const path = require('path');

module.exports = {
    mode: 'development', // 模式 默認值:production [development]
    entry: './src/index.js',  // 打包入口文件
    output: {
        filename: 'bundle.[hash:8].js', // 打包後的文件名
        path: path.resolve(__dirname, 'dist') // 這個路徑必須是一個絕對路徑,因此須要用path來解析一下
    }
}
// src/index.js
console.log('hello webpack4.0');

npx webpack 命令直接打包(npm5.2以後支持的語法)。會打包出一個main.js文件前端

默認支持js模塊化:java

// commonjs
// src/a.js
module.exports = 'FinGet'
// src/index.js
let name = require('./a.js');
console.log(name); // 'FinGet'
// ES6 module
// src/a.js
export default = 'FinGet'
// src/index.js
import name from './a.js'
console.log(name); // 'FinGet'

手動配置webpack

  • 默認配置文件的名字: webpack.config.js。爲啥叫這個名字呢?
// node_modules/webpack-cli/bin/config/config-yargs.js
...

module.exports = function(yargs) {
  yargs
    .help("help")
    .alias("help", "h")
    .version()
    .alias("version", "v")
    .options({
      config: {
        type: "string",
        describe: "Path to the config file",
        group: CONFIG_GROUP,
        defaultDescription: "webpack.config.js or webpackfile.js", // 默認名字有兩種
        requiresArg: true
      },
...
  • 能夠經過--config指定配置文件:
npx webpack --config xxxx.js
  • 也能夠在package.json中配置腳本
"script": {
  "build": "webpack --config webpack.config.my.js"
},

運行 npm run buildnode

  • 若是在package.json中不設置config文件
"script": {
  "build": "webpack"
},

運行 npm run build -- --config webpack.config.my.js
-- 不能少!react

  • 簡化的webpack打包出來的文件:
(function(modules) { // webpackBootstrap
  // The module cache 先定義一個緩存
  var installedModules = {};
  // The require function 配置了一個require方法
  function __webpack_require__(moduleId) {

    // Check if module is in cache 檢查這個模塊是否在緩存中
    if (installedModules[moduleId]) {
        return installedModules[moduleId].exports;
    }
    // Create a new module (and put it into the cache) 建立一個新的模塊,並存入緩存
    var module = installedModules[moduleId] = {
        i: moduleId,
        l: false,
        exports: {}
    };

    // Execute the module function
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

    // Flag the module as loaded
    module.l = true;

    // Return the exports of the module
    return module.exports;
  }
  // Load entry module and return exports 加載入口模塊
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
        // key-value  key -> 模塊路徑 | value -> 函數
    "./src/a.js": (function(module, exports) {
        eval("module.exports=\"FinGet\";\n\n//# sourceURL=webpack:///./src/a.js?");
    }),
    "./src/index.js": (function(module, exports, __webpack_require__) {
        eval("let name = __webpack_require__(/*! ./a.js */ \"./src/a.js\");\nconsole.log('hello webpack4.0');\nconsole.log(name);\n\n//# sourceURL=webpack:///./src/index.js?");
    })

});

webpack-dev-server

yarn add webpack-dev-server -Djquery

它會在內存中生成打包文件。webpack

官方文檔: https://webpack.docschina.org/configuration/dev-server/css3

本地服務

// webpack.config.js
// 開發服務器的配置 官方文檔: https://webpack.docschina.org/configuration/dev-server/
devServer: {
    contentBase: './dist', // 告訴服務器從哪一個目錄中提供內容。只有在你想要提供靜態文件時才須要。
    publicPath: './dist', // 將用於肯定應該從哪裏提供 bundle,而且此選項優先。 此路徑下的打包文件可在瀏覽器中訪問。
    port: 3000, // 端口
    progress: true, // 打包過程
    open: true, // 自動打開瀏覽器
    compress: true, // 一切服務都啓用 gzip 壓縮
    // host: '' , // 指定使用一個 host
    hot: true, // 啓用 webpack 的 模塊熱替換 功能 依賴於HotModuleReplacementPlugin
}

plugins: [
  // 開啓webpack全局熱更新
  new webpack.HotModuleReplacementPlugin()
]

作代理

devServer : {
      proxy: { // 代理
      '/api': {
          target: 'http://localhost:3000',
          pathRewrite: {'^/api' : ''}
      }
    }
}

mock數據

devServer: {
  // 前端mock數據 不存在跨域
  before(app) {
    app.get('/api/goods', (req, res) => {
       res.json({
         code: 0,
         list: [
           {id:1,name:'蘋果'},
           {id:2,name:'香蕉'}
        ]
       })
     })
  }
}

html-webpack-plugin

yarn add html-webpack-plugin -D

plugins: [
  new HtmlWebpackPlugin({
    template: path.resolve(__dirname,'./public/index.html'), // 模版路徑
    filename: 'index.html', // 打包後的文件名
    title: 'webpack4.0', // 顧名思義,設置生成的 html 文件的標題
    /**  
        注入選項。有四個選項值 true, body, head, false
        
        true 默認值,script標籤位於html文件的 
        body 底部body 同 true
        head script 標籤位於 head 標籤內
        false 不插入生成的 js 文件,只是單純的生成一個 html 文件
    */
    inject: true, 
    // favicon: 'xxx.ico' // 給生成的 html 文件生成一個 favicon
    minify: { // 壓縮
        removeAttributeQuotes: true, // 去掉屬性的雙引號
        collapseWhitespace: true // 代碼壓縮成一行
    },
    hash: true, // hash選項的做用是 給生成的 js 文件一個獨特的 hash 值,該 hash 值是該次 webpack 編譯的 hash 值
    cahe: true, // 默認值是 true。表示只有在內容變化時才生成一個新的文件
    showErrors: true, // 若是 webpack 編譯出現錯誤,webpack會將錯誤信息包裹在一個 pre 標籤內,屬性的默認值爲 true 

    /**
        chunks 選項的做用主要是針對多入口(entry)文件。當你有多個入口文件的時候,對應就會生成多個編譯後的 js 文件。那麼 chunks 選項就能夠決定是否都使用這些生成的 js 文件。
        chunks 默認會在生成的 html 文件中引用全部的 js 文件,固然你也能夠指定引入哪些特定的文件。
    **/
    // chunks: ['index','index2'], 
  })
]

css樣式

yarn add css-loader style-loader less less-loader -D

在index.js中引入css|less模塊

// src/index.js
let name = require('./a.js');
require('./assets/css/index.css');
require('./assets/css/commom.less');
console.log('hello webpack4.0');
console.log(name);
module: { // 模塊
  rules: [
    // loader的順序 默認是從右往左,從上到下
    // css-loader 解析 @import 這種語法的
    // style-loader 將css引入html的head中 style標籤
    // {test: /\.css$/, use: ['style-loader','css-loader']}
    {test: /\.(css|less)$/, 
      use: [
        {
          loader: 'style-loader',
          options: {
            insertAt: 'top' // 插入頂部 這樣就會被後面的樣式覆蓋
          }
        },
        'css-loader',
        'less-loader'
      ]
    }
  ]
},

mini-css-extract-plugin

yarn add mini-css-extract-plugin -D

上面打包css會把css文件以style標籤的形式寫入index.html,如今咱們就來把它們單獨打包成文件。

module: { // 模塊
    rules: [
        {test: /\.(css|less)$/, 
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'less-loader'
            ]
        }
    ]
}, 

plugins: [
      new MiniCssExtractPlugin({
        filename: 'assets/css/index.css' // 打包到dist/assets/css/index.css
    })
]

css3 自動添加各類瀏覽器前綴:

yarn add postcss-loader autoprefixer -D

// postcss.config.js
module.exports = {
    plugins: [require('autoprefixer')({'browsers': ['> 1%', 'last 2 versions']})]
}

// webpack.config.js
module: { // 模塊
    rules: [
        {test: /\.(css|less)$/, 
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'postcss-loader',
                'less-loader'
            ]
        }
    ]
},

推薦用法是在package.json中設置:

Replace Autoprefixer browsers option to Browserslist config.
Use browserslist key in package.json or .browserslistrc file.
// postcss.config.js
module.exports = {
    plugins: [require('autoprefixer')]
}
"browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]

壓縮css:

⚠️壓縮css也要壓縮js,不如js不會壓縮。

yarn add optimize-css-assets-webpack-plugin terser-webpack-plugin -D

// webpack.config.js
mode:'production', // * development不會壓縮
optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },

處理js

yarn add babel-loader @babel/babel-core @babel/preset-env -D

⚠️ @babel/babel-core@babel/preset-envbabel-core
babel-preset-env 不同
// webpack.config.js
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: '/node_modules',
      include: 'src',
      use: {
        loader: 'babel-loader',
        options: {
            // 配置預設
            presets: [
                '@babel/preset-env'
            ]
        }
      }
    }
  ]
}

或者:

// .babelrc
{
  "presets": ["@babel/preset-env"]
}

處理高級版本js

babel-runtime 是供編譯模塊複用工具函數,是錦上添花。
babel-polyfil是雪中送炭,是轉譯沒有的api。

詳細講解

// 示例
class Person{
    constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

let person = new Person('FinGet',24);
console.log(person.name);

// 高級api
console.log('FinGet'.includes('Get'));
yarn add @babel/plugin-transform-runtime -D
// @babel/runtime as a production dependency (since it's for the "runtime").
yarn add @babel/runtime

使用:

// .babelrc
"plugins": ["@babel/plugin-transform-runtime"]
@babel/runtime 會在打包的js中,注入一些腳本,因此要安裝production依賴
yarn add @babel/polyfill

使用:

require("@babel/polyfill");
// or 
import "@babel/polyfill";
// or
// webpack.config.js
module.exports = {
  entry: ["@babel/polyfill", "./app/js"],
};
這樣引入會致使打包出來的js很大

按需引入:

// .babelrd
{
  "presets": [["@babel/preset-env", {
    "useBuiltIns": "usage" 
  }]],
}

關鍵點是useBuiltIns這一配置項,它的值有三種:

  • false: 不對polyfills作任何操做
  • entry: 根據target中瀏覽器版本的支持,將polyfills拆分引入,僅引入有瀏覽器不支持的polyfill
  • usage(新):檢測代碼中ES6/7/8等的使用狀況,僅僅加載代碼中用到的polyfills

ESlint 檢測語法

yarn add eslint eslint-loader -D

https://cn.eslint.org/demo/

在根目錄下生成一個.eslint.json來配置規則。

{
    "parserOptions": {
        "ecmaVersion": 5,
        "sourceType": "script",
        "ecmaFeatures": {}
    },
    "rules": {
        // 容許console
        "no-console": "off",
        // 容許空語句塊
        "no-empty": ["error", { "allowEmptyCatch": true }],
        // 強制關鍵字周圍空格的一致性 (keyword-spacing)
        "keyword-spacing": "error",
        // 把 var 語句看做是在塊級做用域範圍以內
        "block-scoped-var": "error",
        // 要求遵循大括號約定
        "curly": "error",
        // switch 要有default分支
        "default-case": "error",
        // no-eq-null 禁止與null進行比較
        "no-eq-null": "error",
        // 禁止使用多個空格
        "no-multi-spaces": ["error", {"exceptions": { "Property": true }}],
        // 禁止多行字符串
        "no-multi-str": "error",
        // 禁止使用 new 以免產生反作用
        "no-new": "error",
        // 數組中的空格
        "array-bracket-spacing": ["error", "never"],
        // 禁止或強制在代碼塊中開括號前和閉括號後有空格
        "block-spacing": "error",
        // 大括號風格要求
        "brace-style": ["error",  "1tbs", { "allowSingleLine": true }],
        // 逗號先後使用一致的空格
        "comma-spacing": ["error", { "before": false, "after": true }],
        // 逗號風格
        "comma-style": ["error", "last"],
        // 計算屬性不使用空格
        "computed-property-spacing": ["error", "never"],
        // 函數標識符和其調用之間禁止空格
        "func-call-spacing": ["error", "never"],
        // 箭頭函數函數體的位置
        "implicit-arrow-linebreak": ["error", "beside"],
        // tab縮進
        "indent": ["error", "tab", { "SwitchCase": 1 }],
        // 對象key-value空格
        "key-spacing": ["error", { "beforeColon": false }],
        // 行註釋位置
        "line-comment-position": ["error", { "position": "above" }],
        // 類成員之間須要空行
        "lines-between-class-members": ["error", "always"],
        // 要求構造函數首字母大寫
        "new-cap": "error",
        // 調用無參構造函數時帶括號
        "new-parens": "error",
        // 禁止使用 Array 構造函數
        "no-array-constructor": "error",
        // 禁止使用內聯註釋
        "no-inline-comments": "error",
        // 禁止連續賦值
        "no-multi-assign": "error",
        // 不容許多個空行
        "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
        // 禁止使用 Object 構造函數
        "no-new-object": "error",
        // 禁用行尾空白
        "no-trailing-spaces": "error",
        // 禁止屬性前有空白
        "no-whitespace-before-property": "error",
        // 強制在花括號內使用一致的換行符
        "object-curly-newline": ["error", { "ImportDeclaration": "always", "ExportDeclaration": "always" }],
        // 花括號中使用一致的空格
        "object-curly-spacing": ["error", "never"],
        // 要求在變量聲明周圍換行
        "one-var-declaration-per-line": ["error", "always"],
        // 禁止塊內填充
        "padded-blocks": ["error", "never"],
        // 語句間填充空行
        "padding-line-between-statements": [
            "error",
            { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*"},
            { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},
            { "blankLine": "always", "prev": "directive", "next": "*" },
            { "blankLine": "any", "prev": "directive", "next": "directive" }
        ],
        // 強制使用一致的反勾號、雙引號或單引號
        "quotes": ["error", "single", { "allowTemplateLiterals": true }],
        // 對象字面量屬性名稱使用引號
        "quote-props": ["error", "as-needed"],
        // 行尾分號
        "semi": ["error", "always"],
        // 分號先後空格
        "semi-spacing": ["error", {"before": false, "after": true}],
        // 分號位置
        "semi-style": ["error", "last"],
        // 語句塊以前的空格
        "space-before-blocks": "error",
        // function空格
        "space-before-function-paren": ["error", {
            "anonymous": "always",
            "named": "never",
            "asyncArrow": "always"
        }],
        // 禁止圓括號內的空格
        "space-in-parens": "error",
        // 要求中綴操做符周圍有空格
        "space-infix-ops": "error",
        // 要求或禁止在一元操做符以前或以後存在空格
        "space-unary-ops": ["error", {"words": true, "nonwords": false}],
        // 要求或禁止在註釋前有空白
        "spaced-comment": ["error", "always"],
        // 強制在 switch 的冒號左右有空格
        "switch-colon-spacing": "error",
        // 要求正則表達式被包裹起來
        "wrap-regex": "error",

        // ES6
        // 要求箭頭函數體使用大括號
        "arrow-body-style": "error",
        // 要求箭頭函數的箭頭以前或以後有空格
        "arrow-spacing": "error",
        // 禁止重複導入
    },
    "env": {}
}
{
  test: /\.js$/,
  loader: ['babel-loader', 'eslint-loader'],
}
// or 
{
  test: /\.js$/,
  use: {
    loader: 'eslint-loader',
    options: {
      enforce: 'pre' // 先執行
    }
  }
}

打包圖片

  • js中建立圖片引入
import jpg from './assets/snail.jpg'
let img = new Image();
img.src = jpg 

document.body.appendChild(img);
  • css背景圖引入
body{
    background-image: url(../logo.svg);
}
  • html img標籤引入
<img src="../src/assets/snail.jpg" alt="">

file-loader

yarn add file-loader -D

file-loader 會默認在內部生成生成一張圖片,到dist目錄下,把生成圖片的名字返回回來

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use: 'file-loader' 
}

html-withimg-loader

html中直接使用img標籤src加載圖片的話,由於沒有被依賴,圖片將不會被打包。
yarn add html-withimg-loader

使用:

{
  test: /\.(htm|html)$/i,
  loader: 'html-withimg-loader'
}

url-loader

若是圖片較多,會發不少http請求,會下降頁面性能。這個問題能夠經過url-loader解決。url-loader會將引入的圖片編碼,生成dataURl。至關於把圖片數據翻譯成一串字符。再把這串字符打包到文件中,最終只須要引入這個文件就能訪問圖片了。固然,若是圖片較大,編碼會消耗性能。所以url-loader提供了一個limit參數,小於limit字節的文件會被轉爲DataURl,大於limit的還會使用file-loader進行copy。

url-loader和file-loader是什麼關係呢?簡答地說,url-loader封裝了file-loader。url-loader不依賴於file-loader,即便用url-loader時,只須要安裝url-loader便可,不須要安裝file-loader,由於url-loader內置了file-loader。
yarn add url-loader -D
{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use: {
      loader: 'url-loader',
      options: {
          name: '[name].[ext]', // 保持名稱不變
          limit: 20*1024, // 小於20k的圖片 打包成base64
          outputPath: 'assets/' // 打包後的存放路徑 dist/assets
      } 
  }
},

output.publicPath

此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」。相對 URL(relative URL) 會被相對於 HTML 頁面(或 <base> 標籤)解析。相對於服務的 URL(Server-relative URL),相對於協議的 URL(protocol-relative URL) 或絕對 URL(absolute URL) 也但是可能用到的,或者有時必須用到,例如:當將資源託管到 CDN 時。
module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'https://cdn.example.com/assets/'
  }
};

⚠️也能夠單獨給圖片的options下配一個publicPath

source-map

生產模式會壓縮代碼成一行,就無法調試了。

...
️mode:'developmen', //production 不會生成map文件
entry: './src/index.js',
devtool: "source-map", // 增長映射文件
...

webpack 高級配置

watch

...
entry: entry: './src/index.js',
// build 監控,變化自動打包
watch: true,
watchOptions: { // 監控選項
  poll: 1000, // 每秒 watch 1000次
  aggregateTimeout: 500, // 防抖
  ignored: '/node_modules/' //不須要監控的文件
},
...

clean-webpack-plugin

每次打包以前,都刪除dist目錄下的文件。

yarn add clean-webpack-plugin -D

clean-webpack-plugin: ^3.00

const {CleanWebpackPlugin} = require('clean-webpack-plugin');

plugins: [    
    new CleanWebpackPlugin()  
]
export { CleanWebpackPlugin };//3.0.0導出方式

export default CleanWebpackPlugin;//2.0.2導出方式
因此在2.0.2版本咱們能夠直接require拿到CleanWebpackPlugin 
const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = CleanWebpackPlugin;//1.0.1導出方式
他會默認清空咱們output裏面設置的全部文件夾
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional

By default, this plugin will remove all files inside webpack's output.path directory, as well as all unused webpack assets after every successful rebuild.

copy-webpack-plugin

拷貝文件

yarn add copy-webpack-plugin -D
const CopyPlugin = require('copy-webpack-plugin');

plugins: [
  new CopyPlugin([
    { from: 'src/assets', to: 'assets' }
  ]),
]

BannerPlugin

版權聲明

plugins:[
  new webpack.BannerPlugin('CopyRight by FinGet!')
]
// 會在打包文件頭部加上 /*! CopyRight by FinGet! */
// 配置選項
{
  banner: string | function, // 其值爲字符串或函數,將做爲註釋存在
  raw: boolean, // 若是值爲 true,將直出,不會被做爲註釋
  entryOnly: boolean, // 若是值爲 true,將只在入口 chunks 文件中添加
  test: string | RegExp | Array,
  include: string | RegExp | Array,
  exclude: string | RegExp | Array,
}

resolve

module.exports = {
  resolve: { // 解析第三方包
    alias: { // 建立 import 或 require 的別名,來確保模塊引入變得更簡單。
      '@': path.resolve(__dirname, 'src')
    },
    extensions: ['.js','.css','.json'], // 自動解析肯定的擴展 就是沒有後綴名時,按這個順序匹配
    modules: [path.resolve('node_modules')] //告訴 webpack 解析模塊時應該搜索的目錄
  },
}

點這裏查看更多配置項。

DefinePlugin

定義一些全局變量。

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      PRODUCTION: JSON.stringify(true),
      VERSION: JSON.stringify('5fa3b9'),
      BROWSER_SUPPORTS_HTML5: true,
      TWO: '1+1',
      'typeof window': JSON.stringify('object'),
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    });
  ]
}
注意,由於這個插件直接執行文本替換,給定的值必須包含字符串自己內的實際引號。一般,有兩種方式來達到這個效果,使用 '"production"', 或者使用 JSON.stringify('production')。

webpack-merge

分別配置不一樣的環境打包文件。

yarn add webpack-merge -D
// build/webpack.base.conf.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: path.resolve(__dirname,'../src/index.js'), // 打包入口文件
  output: {
    filename: 'bundle.[hash:8].js', // 打包後的文件名
    path: path.resolve(__dirname, '../dist') // 這個路徑必須是一個絕對路徑,因此須要用path來解析一下
  },
  module: { // 模塊
    rules: [
      {
        test: /\.(css|less)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 1,
            outputPath: 'assets/images' // 打包後的存放路徑
          }
        }
      },
      {
        test: /\.(htm|html)$/i,
        loader: 'html-withimg-loader'
      }
    ]
  },

  // 配置插件

  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html'), // 模版路徑
      filename: 'index.html', // 打包後的文件名
      title: 'webpack4.0', // 顧名思義,設置生成的 html 文件的標題
      inject: true,
      hash: true, // hash選項的做用是 給生成的 js 文件一個獨特的 hash 值,該 hash 值是該次 webpack 編譯的 hash 值
      cahe: true, // 默認值是 true。表示只有在內容變化時才生成一個新的文件
      showErrors: true, // 若是 webpack 編譯出現錯誤,webpack會將錯誤信息包裹在一個 pre 標籤內,屬性的默認值爲 true 
    }),
    new MiniCssExtractPlugin({
      filename: 'assets/css/index.css'
    })
  ]
}
// build/webpack.pro.cong.js
const merge = require('webpack-merge');
const base = require('./webpack.base.conf');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

mmodule.exports = merge(base, {
    mode: 'production',
    optimization: {
      minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    },
    plugins: [
        // 文件頭部注入
      new webpack.BannerPlugin('CopyRight by FinGet!')
    ]
})
// build/webpack.dev.cong.js
const merge = require('webpack-merge');
const webpack = require('webpack');
const base = require('./webpack.base.conf');

mmodule.exports = merge(base, {
  mode: 'development',
  // 開發服務器的配置 官方文檔: https://webpack.docschina.org/configuration/dev-server/
  devServer: {
    contentBase: path.resolve(__dirname, "../dist"), // 告訴服務器從哪一個目錄中提供內容。只有在你想要提供靜態文件時才須要。
    // publicPath: './dist', // 將用於肯定應該從哪裏提供 bundle,而且此選項優先。 此路徑下的打包文件可在瀏覽器中訪問。
    port: 3000, // 端口
    progress: true, // 打包過程
    open: true, // 自動打開瀏覽器
  },
  devtool: 'source-map',
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }
    })
  ],
})
yarn run dev -- --config build/webpack.dev.conf.js


yarn run build -- --config build/webpack.pro.conf.js

webpack 優化

noParse

防止 webpack 解析那些任何與給定正則表達式相匹配的文件。

module.exports = {
  //...
  module: {
    noParse: /jquery|lodash/,
  }
};

happyPack 多線程打包

js、css、img均可以多線程打包,提升打包速度。

yarn add happypack -D
module.exports = {
 module:{
   {
     test: /\.js$/,
     use: 'Happypack/loader?id=js'
   }
 }
 plugins:[
   new Happypack({
     id: 'js', // id與上面對應
     use: [{
       loader: 'babel-loader',
       options: {
         presets:['@babel/preset-env']
       }
     }]
   })
 ]
}

tree-shaking

(webpack 自帶)把沒用的代碼刪除掉。

import 在生產環境下 會自動去掉沒用的代碼。es6 模塊會把結果放到 default上。
// test.js
let sum = (a,b) => {
  return a+b;
}
let minus = (a,b) => {
  return a-b;
}
export default {sum,minus}
import calc from './test.js';
console.log(calc.add(1,2));

let calc = require('./test');
console.log(calc.default.sum(1,2));

這裏沒用minus方法,在import方式打包中會tree-shaking,require則不會。

scope hosting

let a = 1;
let b = 2;
let c = 3;
let d = a + b + c;
console.log(d);

這個代碼很囉嗦,在打包以後,webpack會自動分析,省略代碼。

// 打包後
console.log(6);

抽離公共代碼

多入口項目,多個入口,引用同一個js/css,則能夠抽離公共代碼。

module.exports = {
  optimization: {
    splitChunks: { // 分割代碼塊
      cacheGroups: { // 緩存組
        common: { // 公共模塊
          chunks: 'initial',
          minSize: 0,
          minChunks: 2,
        }
      }
    }
  },
}
// 把第三方模塊單獨打包 好比jquery、lodash
module.exports = {
  optimization: {
    splitChunks: { // 分割代碼塊
      cacheGroups: { // 緩存組
        common: { // 公共模塊
          chunks: 'initial',
          minSize: 0,
          minChunks: 2,
        },
        
        // 單獨打包第三方模塊
        vendor: {
          priority: 1, // 優先級別
          test: /[\\/]node_modules[\\/]/,
          chunks: 'initial',
          name(module, chunks, cacheGroupKey) {
            const moduleFileName = module.identifier().split('/').reduceRight(item => item);
            return `${moduleFileName}`;
          },
          minSize: 0,
          minChunks: 2
        }
      }
    }
  },
}

optimization參數介紹:

optimization: {
    splitChunks: { 
      chunks: "initial",         // 代碼塊類型 必須三選一: "initial"(初始化) | "all"(默認就是all) | "async"(動態加載) 
      minSize: 0,                // 最小尺寸,默認0
      minChunks: 1,              // 最小 chunk ,默認1
      maxAsyncRequests: 1,       // 最大異步請求數, 默認1
      maxInitialRequests: 1,     // 最大初始化請求書,默認1
      name: () => {},            // 名稱,此選項課接收 function
      cacheGroups: {                // 緩存組會繼承splitChunks的配置,可是test、priorty和reuseExistingChunk只能用於配置緩存組。
        priority: "0",              // 緩存組優先級 false | object |
        vendor: {                   // key 爲entry中定義的 入口名稱
          chunks: "initial",        // 必須三選一: "initial"(初始化) | "all" | "async"(默認就是異步)
          test: /react|lodash/,     // 正則規則驗證,若是符合就提取 chunk
          name: "vendor",           // 要緩存的 分隔出來的 chunk 名稱
          minSize: 0,
          minChunks: 1,
          enforce: true,
          reuseExistingChunk: true   // 可設置是否重用已用chunk 再也不建立新的chunk
        }
      }
    }
  }

點擊這裏查看更多配置。

懶加載

在用戶觸發一個點擊操做才加載須要的文件。

// lazy.js
export default '懶加載';
// test.js
function handleClick() {
  import('./lazy.js').then(module => {
    console.log(module.default);
  })
}

最後

建立了一個前端學習交流羣,感興趣的朋友,一塊兒來嗨呀!

相關文章
相關標籤/搜索