1、Webpack 從入門到精通-基礎篇

本篇章適合有必定webpack基礎的攻城獅,本人目前是一名學生,處於學習階段,若是有寫的很差的地方歡迎大神指正。javascript

本章主要包含如下幾部份內容:css

  • Webpack 簡介html

  • Webpack 初體驗前端

  • Webpack 開發環境的基本配置vue

  • Webpack 生產環境的基本配置java

  • Webpack 優化配置node

  • Webpack 配置詳情react

  • Webpack5 使用jquery

你們學完以後若是覺着意猶未盡能夠繼續學習Webpack 從入門到精通-進階篇,進階篇主要講述以下內容:webpack

  • React/Vue腳手架的詳細配置
  • 基於Webpack5自定義loader/plugin
  • 本身實現一個簡易的Webpack5

這邊主要講解了經常使用的Webpack配置,更詳細的配置你們能夠查看官網Webpack官網

Webpack 從入門到精通-基礎篇源碼

下面進入正題

1、webpack 簡介

1.1 webpack 是什麼

webpack 是一種前端資源構建工具,一個靜態模塊打包器(module bundler)。 在 webpack 看來, 前端的全部資源文件(js/json/css/img/less/...)都會做爲模塊處理。 它將根據模塊的依賴關係進行靜態分析,打包生成對應的靜態資源(bundle)。

1.2 webpack 五個核心概念

1.2.1 Entry

入口(Entry)指示 webpack 以哪一個文件爲入口起點開始打包,分析構建內部依賴圖。

1.2.2 Output

輸出(Output)指示 webpack 打包後的資源 bundles 輸出到哪裏去,以及如何命名。

1.2.3 Loader

Loader:讓 webpack 可以去處理那些非 JS 的文件,好比樣式文件、圖片文件(webpack 自身只理解JS)

1.2.4 Plugins

插件(Plugins):能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量等。

1.2.5 Mode

模式(Mode):指示 webpack 使用相應模式的配置。

選項 描述 特色
development 會將 DefinePlugin 中 process.env.NODE_ENV 的值設置爲 development。啓用 NamedChunksPlugin 和 NamedModulesPlugin。 能讓代碼本地調試運行的環境
production 會將 DefinePlugin 中 process.env.NODE_ENV 的值設置爲 production。啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。 能讓代碼優化上線運行的環境

2、Webpack 初體驗

2.1 初始化配置

  1. 初始化package.json文件

輸入指令:npm init 2. 下載並安裝 webpack 輸入指令: npm install webpack webpack-cli -g(全局安裝)(即便之前安裝過,如今也是能夠安裝的,會對之前的進行更新) npm install webpack webpack-cli -D(本地安裝)

2.2 編譯打包應用

  1. 建立文件
  2. 運行指令

開發環境指令:webpack src/js/index.js -o build/js/built.js --mode=development 功能:webpack 可以編譯打包 js 和 json 文件,而且能將 es6 的模塊化語法轉換成 瀏覽器能識別的語法。 生產環境指令:webpack src/js/index.js -o build/js/built.js --mode=production 功能:在開發配置功能上多一個功能,壓縮代碼。 3. 結論 webpack 可以編譯打包 js 和 json 文件。 能將 es6 的模塊化語法轉換成瀏覽器能識別的語法。 能壓縮代碼。 4. 問題 不能編譯打包 css、img 等文件。 不能將 js 的 es6 基本語法轉化爲 es5 如下語法。

3、webpack 開發環境的基本配置

3.1 建立配置文件

  1. 建立文件 webpack.config.js
  2. 配置內容以下
const { resolve } = require('path'); // node 內置核心模塊,用來處理路徑問題。

module.exports = {
  entry: './src/js/index.js',
  // 入口文件
  output: {
    // 輸出配置
    filename: './built.js',
    // 輸出文件名
    path: resolve(__dirname, 'build/js')// 輸出文件路徑配置
  },
  mode: 'development'//開發環境
};
複製代碼
  1. 運行指令: webpack
  2. 結論: 此時功能與上節一致

3.2 打包樣式資源

  1. 建立文件
  2. 下載安裝包

npm i css-loader style-loader less-loader less -D

  1. 修改配置文件webpack.config.js
/* webpack.config.js webpack的配置文件(src裏面寫項目代碼,webpack寫配置代碼) 做用: 指示 webpack 幹哪些活(當你運行 webpack 指令時,會加載裏面的配置) 全部構建工具都是基於nodejs平臺運行的~模塊化默認採用commonjs。 */

// resolve用來拼接絕對路徑的方法
const {
  resolve
} = require('path');

module.exports = {
  // webpack配置
  // 入口起點
  entry: './src/index.js',
  // 輸出(輸出到build文件夾下面的built.js文件中)
  output: {
    // 輸出文件名
    filename: 'built.js',
    // 輸出路徑
    // __dirname nodejs的變量,表明當前文件的目錄絕對路徑(表示的是與當前webpack.config.js平級的build文件夾)
    path: resolve(__dirname, 'build')
  },
  // loader的配置
  module: {
    rules: [
      // 詳細loader配置
      // 不一樣文件必須配置不一樣loader處理
      {
        // 匹配哪些文件
        test: /\.css$/,
        // 使用哪些loader進行處理
        use: [
          // use數組中loader執行順序:從右到左,從下到上 依次執行
          // 建立style標籤,將js中的樣式資源插入進行,添加到head中生效
          'style-loader',
          // 將css文件變成commonjs模塊加載js中,裏面內容是樣式字符串
          'css-loader'
        ]
      }, {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          // 將less文件編譯成css文件
          // 須要下載 less-loader和less
          'less-loader'
        ]
      }
    ]
  },
  // plugins的配置
  plugins: [
    // 詳細plugins的配置
  ],
  // 模式(表示使用什麼模式)
  mode: 'development', // 開發模式
  // mode: 'production'
}

/* 執行的步驟:只分析less(安裝loader:style-loader css-loader less-loader less)(css只須要安裝前面兩個loader) 1. 根據entry找到入口文件'./src/index.js' 2. 發現入口文件中引入了.less文件,而.less文件不是js或者json文件,去找module的rules裏面尋找less的loader 3. 找到test: /\.less$/,執行該對象中的rules數組中的代碼(從右到左,從下到上 依次執行) 4. 經過less-loader將less文件編譯成css文件 5. 經過css-loader將css文件變成commonjs模塊加載js中,裏面內容是樣式字符串 6. 經過style-loader建立style標籤,將js中的樣式資源插入進行,添加到head中生效 7. 將代碼添加到出口文件與當前webpack.config.js平級的build文件夾下面的built.js文件中 */
複製代碼
  1. 運行指令:webpack

3.3 打包html資源

  1. 建立文件
  2. 下載安裝包

npm install --save-dev html-webpack-plugin

  1. 修改配置文件webpack.config.js
/* loader: 1. 下載 2. 使用(配置loader) plugins: 1. 下載 2. 引入 3. 使用 */
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
    ]
  },
  plugins: [
    // plugins的配置
    // html-webpack-plugin
    // 功能:默認會建立一個空的HTML,自動引入打包輸出的全部資源(JS/CSS)
    // 需求:須要有結構的HTML文件,須要添加一個template
    new HtmlWebpackPlugin({
      // 複製 './src/index.html' 文件,並自動引入打包輸出的全部資源(JS/CSS)
      template: './src/index.html'
    })
  ],
  mode: 'development'
};
/* 執行的步驟:html(安裝plugin:html-webpack-plugin) 1. 根據entry找到入口文件'./src/index.js' 2. 發現入口文件中引入了html文件,而html文件不是js或者json文件,去plugins數組中找到HtmlWebpackPlugin插件 3. 複製template選項中的文件, 4. 經過less-loader將less文件編譯成css文件,自動引入打包輸出的全部資源(JS/CSS)(JS文件經過script標籤引入,CSS文件經過link標籤引入)(不須要本身再引用了,不然重複引入會出問題的) */
複製代碼
  1. 運行指令:webpack

3.4 打包圖片資源

  1. 建立文件
  2. 下載安裝包

npm install --save-dev html-loader url-loader file-loader

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.less$/,
      // 要使用多個loader處理用use
      use: ['style-loader', 'css-loader', 'less-loader']
    }, {
      // 問題:默認處理不了html中img圖片
      // 處理圖片資源
      test: /\.(jpg|png|gif)$/,
      // 使用一個loader
      // 下載 url-loader file-loader(url-loader依賴於file-loader)
      loader: 'url-loader',
      options: {
        // 圖片大小小於8kb,就會被base64處理(一般小圖片(8-12kb)使用limit進行這種處理,若是有9kb的圖片,咱們能夠將limit寫成10 * 1024)
        // 優勢: 減小請求數量(減輕服務器壓力)
        // 缺點:圖片體積會更大(文件請求速度更慢)
        limit: 8 * 1024,
        // 問題:由於url-loader默認使用es6模塊化解析,而html-loader引入圖片是commonjs
        // 解析時會出問題:[object Module]
        // 解決:關閉url-loader的es6模塊化,使用commonjs解析
        esModule: false,
        // 給圖片進行重命名
        // [hash:10]取圖片的hash的前10位
        // [ext]取文件原來擴展名
        name: '[hash:10].[ext]'
      }
    }, {
      test: /\.html$/,
      // 處理html文件的img圖片,而不是處理html文件的,html文件是用HtmlWebpackPlugin處理的(負責引入img,從而能被url-loader進行處理)
      loader: 'html-loader'
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};
/* 執行的步驟:打包圖片資源(安裝loader:url-loader file-loader html-loader) 1. 根據entry找到入口文件'./src/index.js' 2. 發現入口文件中引入了jpg|png|gif文件,而jpg|png|gif文件不是js或者json文件,去找module的rules裏面尋找jpg|png|gif的loader 3. 找到test: /\jpg|png|gifs$/,執行該對象中的rules數組中的代碼 4. 經過options-->limit對體積進行限制 5. 這種方式只能處理樣式中引入的圖片,不能處理html中引入的圖片,若是要處理htnl中引入的資源,須要使用html-loader 6. 處理html中引入的圖片須要找到test: /\jpg|png|gifs$/,執行裏面的html-loader 7. 可是解析時圖片的名稱會出現[object Module]問題,這是由於url-loader默認使用es6模塊化解析,而html-loader引入圖片是commonjs,使用esModule: false關閉url-loader的es6模塊化,使用commonjs解析便可 8. 使用name: '[hash:10].[ext]'給圖片進行重命名 */
複製代碼
  1. 運行指令:webpack

3.5 打包其餘資源

  1. 建立文件
  2. 下載安裝包

npm install --save-dev file-loader

  1. 修改配置文件webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // 打包其餘資源(除了html/js/css資源之外的資源)
      {
        // 排除css/js/html資源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

複製代碼
  1. 運行指令:webpack

3.6 devserver

  1. 建立文件
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // 打包其餘資源(除了html/js/css資源之外的資源)
      {
        // 排除css/js/html資源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',

  // 要安裝 webpack-dev-server(由於是本地安裝,因此須要使用npx webpack-dev-server啓動,webpack咱們使用的全局安裝,因此啓動的時候不須要使用npx)
  // 開發服務器 devServer:用來自動化(自動編譯,自動打開瀏覽器,自動刷新瀏覽器~~)
  // 特色:只會在內存中編譯打包,不會有任何輸出
  // 啓動devServer指令爲:npx webpack-dev-server
  devServer: {
    // 項目構建後路徑
    contentBase: resolve(__dirname, 'build'),
    // 啓動gzip壓縮(使得打包後的代碼體積更小)
    compress: true,
    // 端口號
    port: 3000,
    // 自動打開瀏覽器
    open: true
  }
};
複製代碼
  1. 運行指令:webpack

3.7 開發環境配置(基本模板)

  1. 建立文件
  2. 下載安裝包

上面3.2-3.6下載的loader/plugin文件

  1. 修改配置文件webpack.config.js
/* 開發環境配置:能讓代碼運行 運行項目指令: webpack 會將打包結果輸出出去 npx webpack-dev-server 只會在內存中編譯打包,沒有輸出 全部的代碼打包輸出到js/built.js文件中 隨着咱們的資源愈來愈多,咱們還須要將代碼分類打包,即是在每個loader中使用outputPath: build文件夾下面的須要放置打包文件的文件夾名 css、less等文件不須要設置專門的outputPath,由於它們是直接打包成字符串放進js文件中的 */

const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 處理less資源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      }, {
        // 處理css資源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }, {
        // 處理圖片資源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 關閉es6模塊化
          esModule: false,
          outputPath: 'imgs'
        }
      }, {
        // 處理html中img資源
        test: /\.html$/,
        loader: 'html-loader'
      }, {
        // 處理其餘資源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true
  }
};
複製代碼
  1. 運行指令:webpack

4、webpack 生產環境的基本配置

4.1 提取 css 成單獨文件

  1. 建立文件
  2. 下載插件安裝包

npm install --save-dev mini-css-extract-plugin

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//使用這個插件的做用:style樣式不是放在style標籤中的,而是經過link的方式使用
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        // 'style-loader'做用:建立style標籤,將樣式放入, 
        // 這個loader取代style-loader。做用:提取js中的css成單獨文件
        MiniCssExtractPlugin.loader,
        // 將css文件整合到js文件中
        'css-loader'
      ]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      // 對輸出的css文件進行重命名
      filename: 'css/built.css'
    })
  ],
  mode: 'development'
};
複製代碼
  1. 運行指令:webpack

4.2 css 兼容性處理

  1. 建立文件
  2. 下載loader安裝包

npm install --save-dev postcss-loader postcss-preset-env

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 設置nodejs環境變量
// process.env.NODE_ENV = 'development';

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        MiniCssExtractPlugin.loader,
        'css-loader',
        /* css兼容性處理:postcss --> postcss-loader postcss-preset-env(做用:postcss-preset-env幫助postcss識別環境從而加載對應的配置,從而使得代碼兼容每個瀏覽器的版本) postcss-preset-env: 幫postcss找到package.json中browserslist裏面的配置,經過配置加載指定的css兼容性樣式 //browserslist要寫在package.json中 "browserslist": { // 開發環境 --> 設置node環境變量:process.env.NODE_ENV = development "development": [ "last 1 chrome version",//兼容最近的版本 "last 1 firefox version", "last 1 safari version" ], // 生產環境:默認是看生產環境 "production": [ ">0.2%", "not dead",//不用已經死的瀏覽器 "not op_mini all"//不用op_mini版本的瀏覽器 ] } */
        // 使用loader的默認配置
        // 'postcss-loader',
        // 修改loader的配置,寫成下面的對象的形式
        {
          loader: 'postcss-loader',
          options: {
            ident: 'postcss',
            plugins: () => [
              // postcss的插件
              require('postcss-preset-env')()
            ]
          }
        }
      ]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    })
  ],
  mode: 'development'
};
複製代碼
  1. 修改package.json
"browserslist": {
            // 開發環境 --> 設置node環境變量:process.env.NODE_ENV = development
            "development": [
              "last 1 chrome version",//兼容最近的版本
              "last 1 firefox version",
              "last 1 safari version"
            ],
            // 生產環境:默認是看生產環境
            "production": [
              ">0.2%",
              "not dead",//不用已經死的瀏覽器
              "not op_mini all"//不用op_mini版本的瀏覽器
            ]
          }
複製代碼
  1. 運行指令:webpack

4.3 壓縮css

  1. 建立文件
  2. 下載插件安裝包

npm install --save-dev optimize-css-assets-webpack-plugin

  1. 修改配置文件webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

// 設置nodejs環境變量
// process.env.NODE_ENV = 'development';

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                // postcss的插件
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    // 壓縮css
    new OptimizeCssAssetsWebpackPlugin()
  ],
  mode: 'development'
};
複製代碼
  1. 運行指令:webpack

4.4 js語法檢查

  1. 建立文件
  2. 下載插件安裝包

npm install --save-dev eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      /* 語法檢查: eslint-loader eslint 注意:只檢查本身寫的源代碼,第三方的庫是不用檢查的 設置檢查規則: package.json中eslintConfig中設置~ "eslintConfig": { "extends": "airbnb-base" } airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint */
      {
        test: /\.js$/,
        exclude: /node_modules/, //排除第三方的代碼,只檢查本身的代碼
        loader: 'eslint-loader',
        options: {
          // 自動修復eslint的錯誤
          fix: true
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};
/* 1. 語法檢查咱們須要使用eslint-loader eslint,因此先下載eslint-loader eslint 2. 使用exclude: /node_modules/排除第三方的代碼,只檢查本身的代碼 3. 語法檢查一般採用airbnb(能夠在網站https://github.com/topics/javascript中找出進行詳細的看裏面的介紹,咱們想要將airbnb庫與eslint結合在一塊兒的話,去npmjs網站中搜索elsint找到eslint-config-airbnb-base,點進去根據需求下載安裝便可,eslint-config-airbnb是能夠檢測react代碼的,用到react編寫代碼的時候可使用這個庫),所以須要下載eslint-config-airbnb-base eslint-plugin-import eslint 4. 在package.json中配置語法檢查採用的標準 5. 檢查出現語法問題的代碼使用fix: true實現自動修復eslint出現的語法錯誤 6. 若是在代碼中使用console.log()等語法,eslint會出現提示警告,此時咱們能夠在console.log()上一行加上一行註釋// eslint-disable-next-line表示下一行eslint全部規則都失效(下一行不進行eslint檢查) */
複製代碼
  1. 配置package.json文件
"eslintConfig": {
    "extends": "airbnb-base",
    "env": {
      "browser": true
    }
  }
複製代碼
  1. 運行指令:webpack

4.5 js兼容性處理

  1. 建立文件
  2. 下載插件安裝包

npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/polyfill core-js

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      /* js兼容性處理:安裝babel-loader @babel/core 兩個庫 1. 基本js兼容性處理 --> 安裝@babel/preset-env庫 問題:只能轉換基本語法,如promise高級語法不能轉換 2. 須要作兼容性處理的就作:按需加載 --> 安裝core-js庫並在presets裏面做以下配置 前兩步驟是咱們經常使用的兼容性處理的方式 3. 所有js兼容性處理 --> 安裝babel-loader @babel/core @babel/preset-env @babel/polyfill 不須要進行配置,只須要在主入口文件中引入 @babel/polyfill便可(import '@babel/polyfill') 問題:我只要解決部分兼容性問題,可是將全部兼容性代碼所有引入,體積太大了,因此咱們不使用這種方式~ */
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          // 預設:指示babel作怎麼樣的兼容性處理
          presets: [
            [
              '@babel/preset-env', {
                // 按需加載
                useBuiltIns: 'usage',
                // 指定core-js版本
                corejs: {
                  version: 3
                },
                // 指定兼容性作到哪一個版本瀏覽器
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ]
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};
複製代碼
  1. 運行指令:webpack

4.6 js壓縮

  1. 建立文件
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  // 生產環境下會自動壓縮js代碼//內部會自動加載一些插件
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack

4.7 html壓縮

  1. 建立文件
  2. 修改配置文件webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      // 壓縮html代碼
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除註釋
        removeComments: true
      }
    })
  ],
  mode: 'production'
};

複製代碼
  1. 運行指令:webpack

4.8 生產環境配置

  1. 建立文件
  2. 下載插件安裝包

下載前面的全部的安裝包

  1. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 定義nodejs環境變量:決定使用browserslist的哪一個環境
process.env.NODE_ENV = 'production';

// 複用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader', {
    // 還須要在package.json中定義browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
        test: /\.css$/,
        use: [...commonCssLoader]
      }, {
        test: /\.less$/,
        use: [...commonCssLoader, 'less-loader']
      },
      /* 正常來說,一個文件只能被一個loader處理。 當一個文件要被多個loader處理,那麼必定要指定loader執行的前後順序: 先執行eslint 在執行babel */
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 優先執行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      }, {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env', {
                useBuiltIns: 'usage',
                corejs: {
                  version: 3
                },
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ]
        }
      }, {
        test: /\.(jpg|png|gif)/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'imgs',
          esModule: false
        }
      }, {
        test: /\.html$/,
        loader: 'html-loader'
      }, {
        exclude: /\.(js|css|less|html|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack

5、webpack 優化配置

webpack性能優化

  • 開發環境性能優化
  • 生產環境性能優化
開發環境性能優化
  • 優化打包構建速度
    • HMR
  • 優化代碼調試
    • source-map
生產環境性能優化
  • 優化打包構建速度
    • oneOf
    • babel緩存
    • 多進程打包
    • externals
    • dll
  • 優化代碼運行的性能
    • 緩存(hash-chunkhash-contenthash)
    • tree shaking
    • code split
    • 懶加載/預加載
    • pwa

5.1 HMR

  1. 建立文件
  2. 修改配置文件webpack.config.js
/* 1.爲何要啓用熱更新? 當咱們改變頁面中的css文件的時候會觸發整個文件包括js文件都會從新打包進行更新,這樣會形成慢的打包速度,這是咱們不想要的結果,因此要進行熱更新,只對修改的那個文件進行從新打包,進行更新。 2.HMR: hot module replacement 熱模塊替換 / 模塊熱替換(在devServer中將hot設置爲true即爲開啓) 做用:一個模塊發生變化,只會從新打包這一個模塊(而不是打包全部模塊) 極大提高構建速度 樣式文件:可使用HMR功能:由於style-loader內部實現了~ js文件:默認不能使用HMR功能 --> 須要修改js代碼,添加支持HMR功能的代碼 注意:HMR功能對js的處理,只能處理非入口js文件的其餘文件。 html文件: 默認不能使用HMR功能.同時會致使問題:html文件不能熱更新了~ (不用作HMR功能,由於只有一個html文件,只要裏面的內容發生變化,文件是必定要更新的) 解決:修改entry入口,將html文件引入,這樣才能夠生效 */

const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: ['./src/js/index.js', './src/index.html'],
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 處理less資源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      }, {
        // 處理css資源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }, {
        // 處理圖片資源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 關閉es6模塊化
          esModule: false,
          outputPath: 'imgs'
        }
      }, {
        // 處理html中img資源
        test: /\.html$/,
        loader: 'html-loader'
      }, {
        // 處理其餘資源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 開啓HMR功能
    // 當修改了webpack配置,新配置要想生效,必須重啓webpack服務
    hot: true
  }
};
複製代碼
  1. js代碼須要在代碼中添加
if (module.hot) {
	// 一旦 module.hot 爲true,說明開啓了HMR功能。 --> 讓HMR功能代碼生效
	module.hot.accept('./print.js', function() {
		// 方法會監聽 print.js 文件的變化,一旦發生變化,其餘模塊不會從新打包構建。
		// 會執行後面的回調函數
		//此處至關因而監聽到print.js發生了變化,執行print()函數
		print();
	});
}
複製代碼
  1. 運行指令:webpack

5.2 source-map

  1. 建立文件
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: ['./src/js/index.js', './src/index.html'],
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 處理less資源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      }, {
        // 處理css資源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }, {
        // 處理圖片資源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 關閉es6模塊化
          esModule: false,
          outputPath: 'imgs'
        }
      }, {
        // 處理html中img資源
        test: /\.html$/,
        loader: 'html-loader'
      }, {
        // 處理其餘資源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    hot: true
  },
  devtool: 'eval-source-map' //使用:直接加上這句話便可
};

/* source-map: 一種 提供源代碼到構建後代碼映射 技術 (若是構建後代碼出錯了,經過映射能夠追蹤源代碼錯誤) [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map source-map:外部 錯誤代碼準確信息 和 源代碼的錯誤位置 inline-source-map:內聯 只生成一個內聯source-map 錯誤代碼準確信息 和 源代碼的錯誤位置 hidden-source-map:外部 錯誤代碼錯誤緣由,可是沒有錯誤位置 不能追蹤源代碼錯誤,只能提示到構建後代碼的錯誤位置 eval-source-map:內聯 每個文件都生成對應的source-map,都在eval 錯誤代碼準確信息 和 源代碼的錯誤位置 nosources-source-map:外部 錯誤代碼準確信息, 可是沒有任何源代碼信息 cheap-source-map:外部 錯誤代碼準確信息 和 源代碼的錯誤位置 只能精確的行 cheap-module-source-map:外部 錯誤代碼準確信息 和 源代碼的錯誤位置 module會將loader的source map加入 內聯 和 外部的區別:1. 外部生成了文件,內聯沒有 2. 內聯構建速度更快 開發環境:速度快,調試更友好 速度快(eval>inline>cheap>...) eval-cheap-souce-map(速度最快) eval-source-map 調試更友好 souce-map(調試最好) cheap-module-souce-map cheap-souce-map --> eval-source-map > :eval-cheap-module-souce-map 生產環境:源代碼要不要隱藏? 調試要不要更友好 內聯會讓代碼體積變大,因此在生產環境不用內聯 nosources-source-map 所有隱藏 hidden-source-map 只隱藏源代碼,會提示構建後代碼錯誤信息 --> source-map() / cheap-module-souce-map 最終總結: 開發環境使用:eval-source-map 生產環境使用:source-map() */
複製代碼
  1. 運行指令:webpack

5.3 oneOf

  1. 建立文件
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

process.env.NODE_ENV = 'production';

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

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      // 優先執行
      enforce: 'pre',
      loader: 'eslint-loader',
      options: {
        fix: true
      }
    }, {
      // 如下loader只會匹配一個(這樣子便不會只須要一個loader的時候將全部的loader遍歷一遍了,能夠提升速度)
      // 注意:不能有兩個配置處理同一種類型文件(好比咱們的bable-loader和eslint-loader都要使用,那麼咱們將eslint-loader提取出來放到oneOf前面,這樣前面的eslint-loader執行完畢以後再從oneOf裏面找到bable-loader執行)
      oneOf: [{
          test: /\.css$/,
          use: [...commonCssLoader]
        }, {
          test: /\.less$/,
          use: [...commonCssLoader, 'less-loader']
        },
        /* 正常來說,一個文件只能被一個loader處理。 當一個文件要被多個loader處理,那麼必定要指定loader執行的前後順序: 先執行eslint 在執行babel */
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env', {
                  useBuiltIns: 'usage',
                  corejs: {
                    version: 3
                  },
                  targets: {
                    chrome: '60',
                    firefox: '50'
                  }
                }
              ]
            ]
          }
        }, {
          test: /\.(jpg|png|gif)/,
          loader: 'url-loader',
          options: {
            limit: 8 * 1024,
            name: '[hash:10].[ext]',
            outputPath: 'imgs',
            esModule: false
          }
        }, {
          test: /\.html$/,
          loader: 'html-loader'
        }, {
          exclude: /\.(js|css|less|html|jpg|png|gif)/,
          loader: 'file-loader',
          options: {
            outputPath: 'media'
          }
        }
      ]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack

5.4 緩存

  1. 建立文件
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/* 緩存: 1. babel緩存 cacheDirectory: true --> 讓第二次打包構建速度更快 2. 文件資源緩存 hash: 每次wepack構建時會生成一個惟一的hash值。 問題: 由於js和css同時使用一個hash值。 若是從新打包,會致使全部緩存失效。(可能我卻只改動一個文件) chunkhash:根據chunk生成的hash值。若是打包來源於同一個chunk,那麼hash值就同樣 問題: js和css的hash值仍是同樣的 由於css是在js中被引入的,因此同屬於一個chunk contenthash: 根據文件的內容生成hash值。不一樣文件hash值必定不同 --> 讓代碼上線運行緩存更好使用(上線代碼的性能優化的) 綜上所述:開啓緩存須要經歷兩個步驟: 1. 設置cacheDirectory: true 2. 在輸出的數組中加上contenthash */

// 定義nodejs環境變量:決定使用browserslist的哪一個環境
process.env.NODE_ENV = 'production';

// 複用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader', {
    // 還須要在package.json中定義browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js', //本節修改的地方
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      // 在package.json中eslintConfig --> airbnb
      test: /\.js$/,
      exclude: /node_modules/,
      // 優先執行
      enforce: 'pre',
      loader: 'eslint-loader',
      options: {
        fix: true
      }
    }, {
      oneOf: [{
          test: /\.css$/,
          use: [...commonCssLoader]
        }, {
          test: /\.less$/,
          use: [...commonCssLoader, 'less-loader']
        },

        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env', {
                  useBuiltIns: 'usage',
                  corejs: {
                    version: 3
                  },
                  targets: {
                    chrome: '60',
                    firefox: '50'
                  }
                }
              ]
            ],
            // 開啓babel緩存
            // 第二次構建時,會讀取以前的緩存
            cacheDirectory: true // 本節修改的位置
          }
        }, {
          test: /\.(jpg|png|gif)/,
          loader: 'url-loader',
          options: {
            limit: 8 * 1024,
            name: '[hash:10].[ext]',
            outputPath: 'imgs',
            esModule: false
          }
        }, {
          test: /\.html$/,
          loader: 'html-loader'
        }, {
          exclude: /\.(js|css|less|html|jpg|png|gif)/,
          loader: 'file-loader',
          options: {
            outputPath: 'media'
          }
        }
      ]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css' //本節修改的地方
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};
複製代碼

3. 運行指令:webpack

5.5 tree shaking

  1. 修改配置文件
const {
  resolve
} = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/* tree shaking:去除無用代碼,使得體積更小 前提:1. 必須使用ES6模塊化 2. 開啓production環境 做用: 減小代碼體積 在package.json中配置 "sideEffects": false 全部代碼都沒有反作用(均可以進行tree shaking) 問題:可能會把css / @babel/polyfill (反作用)文件幹掉,因此採用下面的一行形式 "sideEffects": ["*.css", "*.less"](加上這句話表示不移除css和less文件) */

process.env.NODE_ENV = 'production';

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

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      enforce: 'pre',
      loader: 'eslint-loader',
      options: {
        fix: true
      }
    }, {
      oneOf: [{
        test: /\.css$/,
        use: [...commonCssLoader]
      }, {
        test: /\.less$/,
        use: [...commonCssLoader, 'less-loader']
      }, {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env', {
                useBuiltIns: 'usage',
                corejs: {
                  version: 3
                },
                targets: {
                  chrome: '60',
                  firefox: '50'
                }
              }
            ]
          ],
          cacheDirectory: true
        }
      }, {
        test: /\.(jpg|png|gif)/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'imgs',
          esModule: false
        }
      }, {
        test: /\.html$/,
        loader: 'html-loader'
      }, {
        exclude: /\.(js|css|less|html|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          outputPath: 'media'
        }
      }]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};
複製代碼
  1. 運行指令:webpack

5.5 code split

多入口文件

  1. 修改配置文件
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 單入口打包輸出一個文件,多入口打包輸出多個文件,有幾個入口便打包輸出多少個文件
  // 單入口(單頁面應用程序使用單入口)(開發時單入口應用使用的多)
  // entry: './src/js/index.js',
  entry: {
    // 多入口:有一個入口,最終輸出就有一個bundle(多頁面應用程序使用多入口)
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名(好比上面的entry中名稱爲index,那麼輸出的文件名首部會有index名稱)
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack

單入口文件分割多個文件-1

  1. 修改配置文件
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 單入口
  // entry: './src/js/index.js',
  entry: {
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /* 1. 能夠將node_modules中代碼單獨打包一個chunk最終輸出(將別人的第三方的東西單獨打包,將本身寫的東西單獨打包) 2. 自動分析多入口chunk中,有沒有公共的文件。若是有會打包成單獨一個chunk 3. 這種單入口的形式不常使用 */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack

單入口文件輸出多個出口文件-2(經常使用)

  1. 修改配置文件
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 單入口
  entry: './src/js/index.js',
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /* 1. 單入口的這種形式常用,實現功能:單入口打包輸出多個出口文件,從而使得多個文件並行運行,增長運行速度 2. 這種方式能夠將node_modules中代碼單獨打包一個chunk最終輸出,將入口文件打包輸出一個出口文件,若是想要將某個單獨的文件也打包輸出爲一個文件,則須要進行如下配置: 1. optimization配置 2.在打包的出口文件中對須要單獨打包的文件輸入相關代碼 */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};
複製代碼
  1. 入口文件輸入代碼
function sum(...args) {
  return args.reduce((p, c) => p + c, 0);
}

/* 經過js代碼,讓某個文件被單獨打包成一個chunk import動態導入語法:能將某個文件單獨打包 webpackChunkName: 'test'的做用是命名輸出的打包名稱,不然打包名稱會根據每次打包輸出的id進行命名,每次打包輸出的id不同,名稱也不同 */
import ( /* webpackChunkName: 'test' */ './test')
.then(({ mul, count }) => {
    // 文件加載成功~
    // eslint-disable-next-line
    console.log(mul(2, 5));
  })
  .catch(() => {
    // eslint-disable-next-line
    console.log('文件加載失敗~');
  });

// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
複製代碼
  1. 運行指令:webpack

5.6 懶加載

  1. 修改配置文件
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 單入口
  entry: './src/js/index.js',
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  /* 1. 單入口的這種形式常用,實現功能:單入口打包輸出多個出口文件,從而使得多個文件並行運行,增長運行速度 2. 這種方式能夠將node_modules中代碼單獨打包一個chunk最終輸出,將入口文件打包輸出一個出口文件,若是想要將某個單獨的文件也打包輸出爲一個文件,則須要進行如下配置: 1. optimization配置 2.在打包的出口文件中對須要單獨打包的文件輸入相關代碼 */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  mode: 'production'
};
複製代碼
  1. 入口文件中輸入
console.log('index.js文件被加載了~');

// import { mul } from './test'; 屬於正常加載

document.getElementById('btn').onclick = function() {
	// 懶加載~:當文件須要使用時才加載~
	// 預加載 webpackPrefetch: true:會在使用以前,提早加載js文件 
	// 正常加載能夠認爲是並行加載(同一時間加載多個文件) 
	// 預加載 prefetch:等其餘資源加載完畢,瀏覽器空閒了,再偷偷加載資源(兼容性比較差的)(檢測是不是預加載了能夠經過打開控制檯,查看網絡看出是不是提早加載了)
	/* 1. 一般狀況下懶加載的第一次加載若是加載的文件比較大的話會加載的時間比較長,給用戶形成阻塞的現象 2. 通常不使用預加載,由於兼容性差了一些,通常使用懶加載 3. 懶加載的實現是基於前面的代碼分割的基礎上的,要進行了前面的代碼分割的配置纔可使用懶加載,這個案例實現的功能是點擊按鈕以後再加載test文件中的js代碼 4. 懶加載第一次可能會慢一點,第二次加載便不會慢了,第一次加載會存入緩存中,第二次加載會直接從緩存中加載 */
	import ( /* webpackChunkName: 'test', webpackPrefetch: true */ './test').then(({ mul }) => {
		console.log(mul(4, 5));
	});
};
複製代碼
  1. 運行指令:webpack

5.7 pwa

  1. 下載安裝包

npm install --save-dev workbox-webpack-plugin

  1. 修改配置文件
const {
  resolve
} = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');


const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

/* PWA: 漸進式網絡開發應用程序(離線可訪問) workbox --> workbox-webpack-plugin */

process.env.NODE_ENV = 'production';


module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [

    ]
  },
  plugins: [

    new WorkboxWebpackPlugin.GenerateSW({
      /* 1. 幫助serviceworker快速啓動 2. 刪除舊的 serviceworker 生成一個 serviceworker 配置文件~ */
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};
複製代碼
  1. 入口文件中輸入
import { mul } from './test';
import '../css/index.css';

function sum(...args) {
  return args.reduce((p, c) => p + c, 0);
}

// eslint-disable-next-line
console.log(mul(2, 3));
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));

/* 1. eslint不認識 window、navigator全局變量 解決:須要修改package.json中eslintConfig配置 "env": { "browser": true // 支持瀏覽器端全局變量,若是要支持node的全局變量,則寫"node":true } 2. sw代碼必須運行在服務器上 --> nodejs --> npm i serve -g serve -s build 啓動服務器,將build目錄下全部資源做爲靜態資源暴露出去 */
// 註冊serviceWorker
// 處理兼容性問題
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw註冊成功了~');
      })
      .catch(() => {
        console.log('sw註冊失敗了~');
      });
  });
}
複製代碼

查看註冊的service workers 註冊成功緩存的離線數據 4. 運行指令:webpack

5.8 多進程打包

  1. 下載安裝包

npm install --save-dev thread-loader

  1. 修改配置文件
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');


const WorkboxWebpackPlugin = require('workbox-webpack-plugin');//



module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
    
      {
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              /* 開啓多進程打包。 進程啓動大概爲600ms,進程通訊也有開銷。 只有工做消耗時間比較長,才須要多進程打包 */
              {
                loader: 'thread-loader',
                options: {
                  workers: 2 // 進程2個
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: { version: 3 },
                        targets: {
                          chrome: '60',
                          firefox: '50'
                        }
                      }
                    ]
                  ],
                  cacheDirectory: true
                }
              }
            ]
          },
          {
            test: /\.(jpg|png|gif)/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              outputPath: 'imgs',
              esModule: false
            }
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              outputPath: 'media'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    }),
    new WorkboxWebpackPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};
複製代碼
  1. 運行指令:webpack

5.9 externals

  1. 修改配置文件
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'production',
  externals: {
    // 拒絕jQuery被打包進來,做用: 假如說咱們的jequery使用的是CDN連接,那麼打包的時候jquery不會被打包進來,直接使用CDN連接
    jquery: 'jQuery'
  }
};
複製代碼
  1. 運行指令:webpack

5.10 dll

  1. 建立webpack.dll.js文件並輸入
/* 使用dll技術,對某些庫(第三方庫:jquery、react、vue...)進行單獨打包 當你運行 webpack 時,默認查找 webpack.config.js 配置文件 需求:須要運行 webpack.dll.js 文件 --> webpack --config webpack.dll.js */

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

module.exports = {
  entry: {
    // 最終打包生成的[name] --> jquery
    // ['jquery'] --> 要打包的庫是jquery
    jquery: ['jquery'],
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // 打包的庫裏面向外暴露出去的內容叫什麼名字
  },

  plugins: [
    // 打包生成一個 manifest.json --> 提供和jquery映射
    new webpack.DllPlugin({
      name: '[name]_[hash]', // 映射庫的暴露的內容名稱
      path: resolve(__dirname, 'dll/manifest.json') // 輸出文件路徑
    })
  ],
  mode: 'production'
};
複製代碼
  1. 運行指令:webpack --config webpack.dll.js
  2. 修改配置文件webpack.config.js
const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // 告訴webpack哪些庫不參與打包,同時使用時的名稱也得變~
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')
    }),
    // 將某個文件打包輸出去,並在html中自動引入該資源
    new AddAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname, 'dll/jquery.js')
    })
  ],
  mode: 'production'
};

/* 首先要在webpack.dll.js與webpack.config.js中引入webpack插件 1. 在webpack.dll.js文件中的寫入咱們須要打包的庫以及打包的庫輸出的名字爲何(實現功能:第一次打包以後只要jquery庫名稱不變,下一次不須要在從新打包了,直接使用,提升構建速度)(不只僅是jquery庫,各類庫都要引入) 2. plugin中生成的manifest.json文件表示了jquery的映射關係 3. webpack.config.js中使用DllReferencePlugin告訴webpack哪些文件不須要再從新打包 4. webpack.config.js中使用AddAssetHtmlWebpackPlugin將ebpack.dll.js中打包的資源在html中自動引入 */
複製代碼
  1. 運行指令:webpack

6、webpack配置詳情

6.1 entry

const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/* entry: 入口起點 1. string --> './src/index.js'(用的多) 單入口 打包造成一個chunk。 輸出一個bundle文件。 此時chunk的名稱默認是 main 2. array --> ['./src/index.js', './src/add.js'](通常不用這種形式) 多入口 全部入口文件最終只會造成一個chunk, 輸出出去只有一個bundle文件。 --> 只有在HMR功能中讓html熱更新生效~ 3. object(用的多) 多入口 有幾個入口文件就造成幾個chunk,輸出幾個bundle文件 此時chunk的名稱是 key --> 特殊用法 { // 全部入口文件最終只會造成一個chunk, 輸出出去只有一個bundle文件。 index: ['./src/index.js', './src/count.js'], // 造成一個chunk,輸出一個bundle文件。 add: './src/add.js' } */

module.exports = {
  entry: {
    index: ['./src/index.js', './src/count.js'],
    add: './src/add.js'
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'build')
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development'
};
複製代碼

6.2 output

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    // 文件名稱(指定名稱+目錄)
    filename: 'js/[name].js',
    // 輸出文件目錄(未來全部資源輸出的公共目錄)
    path: resolve(__dirname, 'build'),
    // 全部資源引入公共路徑前綴 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
    publicPath: '/',
    chunkFilename: 'js/[name]_chunk.js', // 非入口chunk的名稱
    // library: '[name]', // 整個庫向外暴露的變量名
    // libraryTarget: 'window' // 變量名添加到哪一個上 browser
    // libraryTarget: 'global' // 變量名添加到哪一個上 node
    // libraryTarget: 'commonjs'
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development'
};

複製代碼

6.3 module

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'js/[name].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        test: /\.css$/,
        // 多個loader用use
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.js$/,
        // 排除node_modules下的js文件
        exclude: /node_modules/,
        // 只檢查 src 下的js文件
        include: resolve(__dirname, 'src'),
        // 優先執行
        enforce: 'pre',
        // 延後執行
        // enforce: 'post',
        // 單個loader用loader
        loader: 'eslint-loader',
        options: {}
      },
      {
        // 如下配置只會生效一個
        oneOf: []
      }
    ]
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development'
};
複製代碼

6.4 resolve

const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/[name].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }]
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development',
  // 解析模塊的規則
  resolve: {
    // 配置解析模塊路徑別名: 優勢簡寫路徑 缺點路徑沒有提示
    alias: {
      $css: resolve(__dirname, 'src/css')
    },
    // 配置省略文件路徑的後綴名
    extensions: ['.js', '.json', '.jsx', '.css'],
    // 告訴 webpack 解析模塊是去找哪一個目錄(不寫這個的話,他會一層一層的往上面找,直到找到位置)
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  }
};
複製代碼

6.5 devserver

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/[name].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'development',
  resolve: {
    alias: {
      $css: resolve(__dirname, 'src/css')
    },
    extensions: ['.js', '.json', '.jsx', '.css'],
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  },
  devServer: {
    // 運行代碼的目錄
    contentBase: resolve(__dirname, 'build'),
    // 監視 contentBase 目錄下的全部文件,一旦文件變化就會 reload
    watchContentBase: true,
    watchOptions: {
      // 監視的時候忽略文件
      ignored: /node_modules/
    },
    // 啓動gzip壓縮,體積小
    compress: true,
    // 端口號
    port: 5000,
    // 域名
    host: 'localhost',
    // 自動打開瀏覽器
    open: true,
    // 開啓HMR功能
    hot: true,
    // 不要顯示啓動服務器日誌信息
    clientLogLevel: 'none',
    // 除了一些基本啓動信息之外,其餘內容都不要顯示
    quiet: true,
    // 若是出錯了,不要全屏提示~,只須要在日誌中打印便可
    overlay: false,
    // 服務器代理 --> 解決開發環境跨域問題
    proxy: {
      // 一旦devServer(5000)服務器接受到 /api/xxx 的請求,就會把請求轉發到另一個服務器(3000)
      '/api': {
        target: 'http://localhost:3000',
        // 發送請求時,請求路徑重寫:將 /api/xxx --> /xxx (去掉/api)
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
};
複製代碼

6.6 optimization

const {
  resolve
} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin')

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build'),
    chunkFilename: 'js/[name].[contenthash:10]_chunk.js'
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }]
  },
  plugins: [new HtmlWebpackPlugin()],
  mode: 'production',
  resolve: {
    alias: {
      $css: resolve(__dirname, 'src/css')
    },
    extensions: ['.js', '.json', '.jsx', '.css'],
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
        // 默認值,能夠不寫,基本上不修改~
        /* minSize: 30 * 1024, // 分割的chunk最小爲30kb,小於30kb的不分割,大於30kb才分割 maxSiza: 0, // 最大沒有限制 minChunks: 1, // 要提取的chunk最少被引用1次 maxAsyncRequests: 5, // 按需加載時並行加載的文件的最大數量 maxInitialRequests: 3, // 入口js文件最大並行請求數量 automaticNameDelimiter: '~', // 名稱鏈接符 name: true, // 可使用命名規則 cacheGroups: { // 分割chunk的組 // node_modules文件會被打包到 vendors 組的chunk中。--> vendors~xxx.js // 知足上面寫的公共規則,如:大小超過30kb,至少被引用一次。 vendors: { test: /[\\/]node_modules[\\/]/, // 優先級 priority: -10 }, default: { // 要提取的chunk最少被引用2次 minChunks: 2, // 優先級 priority: -20, // 若是當前要打包的模塊,和以前已經被提取的模塊是同一個,就會複用,而不是從新打包模塊 reuseExistingChunk: true } }*/
    },
    // 將當前模塊的記錄其餘模塊的hash單獨打包爲一個文件 runtime
    // 解決:修改a文件致使b文件的contenthash變化
    runtimeChunk: {
      name: entrypoint => `runtime-${entrypoint.name}`
    },
    minimizer: [
      // 配置生產環境的壓縮方案:js和css
      new TerserWebpackPlugin({
        // 開啓緩存
        cache: true,
        // 開啓多進程打包
        parallel: true,
        // 啓動source-map
        sourceMap: true
      })
    ]
  }
};
複製代碼

7、webpack5使用

webpack5

此版本重點關注如下內容:

  • 經過持久緩存提升構建性能.
  • 使用更好的算法和默認值來改善長期緩存.
  • 經過更好的樹搖和代碼生成來改善捆綁包大小.
  • 清除處於怪異狀態的內部結構,同時在 v4 中實現功能而不引入任何重大更改.
  • 經過引入重大更改來爲未來的功能作準備,以使咱們可以儘量長時間地使用 v5.

下載

  • npm i webpack@next webpack-cli -D

自動刪除 Node.js Polyfills

早期,webpack 的目標是容許在瀏覽器中運行大多數 node.js 模塊,可是模塊格局發生了變化,許多模塊用途如今主要是爲前端目的而編寫的。webpack <= 4 附帶了許多 node.js 核心模塊的 polyfill,一旦模塊使用任何核心模塊(即 crypto 模塊),這些模塊就會自動應用。

儘管這使使用爲 node.js 編寫的模塊變得容易,但它會將這些巨大的 polyfill 添加到包中。在許多狀況下,這些 polyfill 是沒必要要的。

webpack 5 會自動中止填充這些核心模塊,並專一於與前端兼容的模塊。

遷移:

  • 儘量嘗試使用與前端兼容的模塊。
  • 能夠爲 node.js 核心模塊手動添加一個 polyfill。錯誤消息將提示如何實現該目標。

Chunk 和模塊 ID

添加了用於長期緩存的新算法。在生產模式下默認狀況下啓用這些功能。

chunkIds: "deterministic", moduleIds: "deterministic"

Chunk ID

你能夠不用使用 import(/* webpackChunkName: "name" */ "module") 在開發環境來爲 chunk 命名,生產環境仍是有必要的

webpack 內部有 chunk 命名規則,再也不是以 id(0, 1, 2)命名了

Tree Shaking

  1. webpack 如今可以處理對嵌套模塊的 tree shaking
// inner.js
export const a = 1;
export const b = 2;

// module.js
import * as inner from './inner';
export { inner };

// user.js
import * as module from './module';
console.log(module.inner.a);
複製代碼

在生產環境中, inner 模塊暴露的 b 會被刪除

  1. webpack 如今可以多個模塊以前的關係
import { something } from './something';

function usingSomething() {
  return something;
}

export function test() {
  return usingSomething();
}
複製代碼

當設置了"sideEffects": false時,一旦發現test方法沒有使用,不但刪除test,還會刪除"./something"

  1. webpack 如今能處理對 Commonjs 的 tree shaking

Output

webpack 4 默認只能輸出 ES5 代碼

webpack 5 開始新增一個屬性 output.ecmaVersion, 能夠生成 ES5 和 ES6 / ES2015 代碼.

如:output.ecmaVersion: 2015

SplitChunk

// webpack4
minSize: 30000;
複製代碼
// webpack5
minSize: {
  javascript: 30000,
  style: 50000,
}
複製代碼

Caching

// 配置緩存
cache: {
  // 磁盤存儲
  type: "filesystem",
  buildDependencies: {
    // 當配置修改時,緩存失效
    config: [__filename]
  }
}
複製代碼

緩存將存儲到 node_modules/.cache/webpack

監視輸出文件

以前 webpack 老是在第一次構建時輸出所有文件,可是監視從新構建時會只更新修改的文件。

這次更新在第一次構建時會找到輸出文件看是否有變化,從而決定要不要輸出所有文件。

默認值

  • entry: "./src/index.js
  • output.path: path.resolve(__dirname, "dist")
  • output.filename: "[name].js"

更多內容

github.com/webpack/cha…

參考資料:

  1. 尚硅谷視頻

感謝尚硅谷視頻提供的視頻

  1. 大神筆記
相關文章
相關標籤/搜索