webpack4.x學習筆記

做者 zhangljavascript

webpack是什麼?

webpack是一個模塊打包工具,將每一個資源文件看作是一個個模塊,webpack依據打包規則將全部資源處理後打包到指定文件css

支持的模塊引入規範

  • CommonJS
// 導入
import 模塊名 from 模塊路徑;
// 導出
export default 模塊名;
export const 模塊名 = 模塊內容;
複製代碼
  • CMD
// 導入
var 模塊名 = required(模塊路徑);
// 導出
module.exports = 模塊名;
複製代碼
  • AMD

Mac webpack環境搭建

  1. 安裝nodejs,webpack依賴node.js
    • 進入node官網,點擊帶有LTS字眼按鈕,下載穩定版node
    • 點擊壓縮的安裝包,一直點擊下一步便可,
    • 最後執行node -vnpm -v查看版本號,若是有說明安裝成功,不然卸載,從新執行上訴步驟
  2. 執行npm init,初始化項目,一直按回車鍵,在新建的文件夾會生成一個package.json文件
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "private": true, // 是一個私有項目,不會上傳到npm線上
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
複製代碼
  1. 安裝webpack(個人是4.34.0)
    • 全局安裝(不推薦)
      • npm install webpack webpack-cli -g
      • webpack -v 查看全局webpack版本號
    • 局部安裝(推薦)
      • 進入項目目錄下,執行 npm install webpack webpack-cli
      • npx webpack -v 查看版本號 npx查找的是當前目錄下的webpack
    • 卸載
      • npm uninstall webpack webpack-cli
    • 查看webpack版本記錄
      • npm info webpack

webpack配置文件(webpack.config.js)

const path = require('path'); // 導入node的path模塊

module.exports = {
  entry: './src/index.js', // 打包入口文件
  output: {
    filename: 'bundle.js', // 打包出的文件名
    path: path.resolve(__dirname, 'dist') // 存放打包出的文件路徑(絕對路徑)
  }
};
複製代碼

webpack打包命令

// global
webpack 文件名

// local
npx webpack 文件名
複製代碼

配置npm script(簡化打包命令書寫)

// package.json文件
  "scripts": {
    "bundle": "webpack" 
    // 執行npm run bundle命令,
    // webpack會執行package.json文件下script字段裏bundle對應的映射命令
  }
複製代碼

webpack-cli做用

  • 可以在終端使用webpack命令

webpack打包日誌

Hash: 178b79cd0f5fd66a90e5
Version: webpack 4.34.0     -- webpack版本
Time: 380ms     -- 打包耗時
Built at: 06/18/2019 7:59:32 PM
// 文件名     大小   每個打包的js文件id   每個打包的js文件名
    Asset      Size  Chunks             Chunk Names
bundle.js  1.17 KiB       0  [emitted]  main
Entrypoint main = bundle.js // 入口文件名(mian)
[0] ./src/index.js 203 bytes {0} [built] // 文件索引 文件路徑 文件體積
[1] ./src/Footer.js 79 bytes {0} [built]
[2] ./src/Header.js 79 bytes {0} [built]
[3] ./src/Slider.js 79 bytes {0} [built]
複製代碼

mode項

  • 設置webpack的打包環境
  • development:開發環境,專一於打包速度,不會壓縮和tree sharking代碼
  • production:生成環境,專一於打包後的文件體積,會進行文件壓縮和tree sharking去除無用代碼,減少文件體積

Loader是什麼

打包方案,告訴webpack如何處理特定的文件html

module項配置loader

// package.json
  module: { // 打包的模塊
    // 打包規則
    rules: [{
      test: /\.jpg$/, // 正則匹配使用loader解析的模塊後綴名
      use: {
        loader: 'file-loader' // 用於解析該模塊的loader
      }
    }]
  }
複製代碼

webpack打包流程

  1. 容許npm run bundle(其實是執行webpack打包命令)
  2. webpack查看webpack配置文件,根據配置進行打包
  3. 若是遇到js文件,webpack本身處理解析;若是遇到其餘文件,webpack會將該文件交給module項裏能處理該類文件的loader處理,處理完後,將文件地址返回給引用該文件的變量

使用Loader打包靜態資源(圖片篇)

  • file-loader
    • 做用:將js中引用的文件資源抽離成單獨的文件
{
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'file-loader',
        options: {
         // 佔位符 placeholder
          name: '[name]_[hash].[ext]',
          outputPath: 'images/' // 處理後的文件存放位置: dist/images/xxx.png
        }
      }
    }
複製代碼
  • url-loader
    • 做用:將js中引用的文件資源轉換爲base64格式
{
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/', // 處理後的文件存放位置: dist/images/xxx.png,
          // size > 2.048kb 效果與file-loader一致
          // size < 2.048kb 轉換爲base64字符串放入bundle.js中
          limit: 2048
        }
      }
    }
複製代碼

使用Loader打包靜態資源(樣式篇)

  • less-loader
    • 做用:將less文件轉換爲css文件
{
        test: /\.(c|le)ss/,
        use: ['less-loader']
}
複製代碼
  • postcss-loader
    • 做用:生成css AST樹,方便postcss周邊插件處理css代碼
// webpack配置
{ // 樣式處理
        test: /\.(c|le)ss/,
        use: ['postcss-loader', 'less-loader']
    }
複製代碼
// postcss.config.js配置
module.exports = {
  plugins: [
    require('autoprefixer'), // 自動添加屬性前綴(後編譯器)
  ]
};
複製代碼
  • css-loader
    • 做用:分析多個css文件間的引用關係,將多個css文件合併成一段css
{
        test: /\.(c|le)ss/,
        use: ['css-loader', 'postcss-loader', 'less-loader']
}
複製代碼
  • style-loader
    • 做用:將css-loader處理事後的內容,生成style標籤插入到head標籤裏
{       // loader執行順序爲從上到下,從右到左
        test: /\.(c|le)ss/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
}
複製代碼

使用Loader打包靜態資源(字體篇)

{ // 字體處理
        test: /\.(eot|svg|ttf|woff|woff2)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/font/',
            }
          }
        ]
      }
複製代碼

什麼是Plugins?

一段能擴展webpack功能的代碼,能夠在webpack運行到某個時刻的時候,幫助webpack作一些事情java

  • html-webpack-plugin
    • 做用:根據html模板文件,生成一個新的html,並將打包生成的js引入html文件中
// 導入
const HtmlWebpackPlugin = require('html-webpack-plugin');

  plugins: [
    new HtmlWebpackPlugin({ // 根據模板html, 生成新html文件
      template: 'src/index.html', // html模板
    })
  ]
複製代碼
  • clean-webpack-plugin
    • 做用:刪除文件指定文件夾
// 導入(新版本寫法)
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [
    new CleanWebpackPlugin(), // 刪除當前目錄dist文件夾
  ]
複製代碼

SourceMap配置

打包代碼與源碼之間的一種映射關係,可以讓開發人員快速的定位錯誤發生的位置node

  • source-map:會生成一個.map文件
module.exports = {
  devtool: 'source-map',
};
複製代碼

  • inline-source-map:將map映射以base64格式寫入main.js
module.exports = {
  devtool: 'inline-source-map',
};
複製代碼

  • cheap-source-map:只顯示出錯的行數
module.exports = {
  devtool: 'cheap-source-map',
};
複製代碼

  • eval:使用eval形式執行代碼
module.exports = {
  devtool: 'eval',
};
複製代碼

// development:cheap-module-eval-source-map(推薦)
// production:cheap-module-source-map(推薦)
複製代碼

點擊查看devtool配置項react

WebpackDevServer配置

  • 安裝webpack-dev-server
npm install webpack-dev-server --save-dev
複製代碼
  • 配置執行命令
"scripts": {
    "start": "webpack-dev-server"
 }
複製代碼
  • 配置webpack
devServer: { // 設置開發服務
    contentBase: './dist', // 根目錄
    open: true, // 自動打開瀏覽器
    port: 8080, // 端口號
    proxy: { // 設置接口代理(解決跨域)
      '/api': 'https://localhost:3000'
    }
 }
複製代碼

node環境使用WebpackDevServer功能

  • 安裝express(node的框架)
npm install express --save-dev
複製代碼
  • 安裝webpack-middleware(監聽src目錄下文件變化)
npm install webpack-middleware --save-dev
複製代碼
  • 編寫server.js
const express = require('express');
const webpack = require('webpack');
const WebpackMiddleWare = require('webpack-middleware');
const config = require('./webpack.config');

// 生成express實例(服務器)
const app = express();
// 建立webpack編譯器(可以進行webpack打包)
const complier = webpack(config);

// 使用webpack-middleware插件監聽webpack打包的文件變化
app.use(WebpackMiddleWare(complier, {}));

// 開啓監聽
app.listen(3000, () => {
  console.log('server is running at 3000');
});
複製代碼
  • 配置server執行命令
"scripts": {
    "server": "node server.js"
 }
複製代碼

熱模塊替換(Hot Module Replacement)

實現局部更新,而非瀏覽器頁面刷新webpack

devServer: {
    hot: true, // 開啓HMR
    hotOnly: true, // 不更新瀏覽器
 },
 plugins: [
    new webpack.HotModuleReplacementPlugin()
 ]
  
  // entery文件末尾添加
 if (module.hot) {
  module.hot.accept();
}
複製代碼

配置Babel編譯ES6語法

babel:只能解析ES的語法,而不能解析對象的API,Promise等; @babel/polyfill:解析babel不能解析的部分git

  • 安裝babel-loader、@babel/preset-env、@babel/core、@babel/polyfill
npm install babel-loader @babel/preset-env @babel/core @babel/polyfill
複製代碼
  • 配置
module: {
    rules: [
     { // babel處理
        test: /.js$/,
        exclude: /node_modules/, // 排除文件
        loader: 'babel-loader'
      }
    ]
  }
複製代碼
// .babelrc文件
{
  "presets": [
    [
      "@babel/preset-env", // 將ES5以上的語法轉換爲ES5版本
      {
        "useBuiltIns": "usage" // 按需使用polyfill
      }
    ]
  ]
}
複製代碼
// index.js
import '@babel/polyfill';
複製代碼

使用babel-polyfill可能會形成全局變量名污染,若是有使用babel打包第三方包,則使用transform-runtime方案github

配置React代碼打包環境

  • 安裝react、react-dom
npm install react react-dom --save
複製代碼
  • 安裝@babel/preset-react
npm install @babel/preset-react --save-dev
複製代碼
  • .babelrc配置
{
  "presets": [
    ["@babel/preset-react"]
  ]
}
複製代碼

Tree Sharking

刪除模塊中未使用的內容,減少打包體積(只支持ES Module的引入方式)web

開發環境

  • 配置webpack.config
module.exports = {
    mode: 'development'
    optimization: {
        usedExports: true, // 打包被引用的模塊
    }
};
複製代碼
  • 配置package.json
{
    "sideEffects": false // 全部模塊都進行tree sharking
}
複製代碼

生成環境

  • 配置webpack.config
module.exports = {
    mode: 'production'
};
複製代碼
  • 配置package.json
{
    "sideEffects": false // 全部模塊都進行tree sharking
}
複製代碼

Development和Production模式

  • development(開發模式)
    • 關注打包速度,不會進行代碼壓縮
  • production(生產模式)
    • 關注打包文件體積,會對代碼進行壓縮,tree sharking等操做

根據模式拆分webpack.config文件

  • 安裝webpack-merge用以合併webpack配置文件
npm install webpack-merge --save-dev
複製代碼
  • webpack.common.js:公共配置
const path = require('path'); // 導入node的path模塊
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    main: './src/index.js', // 打包入口文件
  },
  output: {
    filename: 'script/[name].js', // 打包出的文件名
    path: path.join(__dirname, '../', 'dist'), // 存放打包出的文件路徑(絕對路徑)
    // publicPath: './', // 公共路徑
  },
  module: { // 打包模塊
    // 打包規則
    rules: [
      { // babel處理
        test: /.js$/,
        exclude: /node_modules/, // 排除文件
        loader: 'babel-loader'
      },
      { // 圖片處理
        test: /\.(jpg|png|gif)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: '[name]_[hash].[ext]',
            outputPath: 'images/', // 處理後的文件存放位置: dist/images/xxx.png
            limit: 10240, // 當處理的文件大小大於2048kb,效果與file-loader一致;小於時,轉換爲base64字符串放入bundle.js中
          }
        }
      }, { // 字體處理
        test: /\.(eot|svg|ttf|woff|woff2)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name]_[hash].[ext]',
              outputPath: 'font/',
            }
          }
        ]
      }, { // csv文件處理
        test: /\.(csv|tsv)$/,
        use: ['csv-loader']
      }, { // xml文件處理
        test: /\.xml$/,
        use: ['xml-loader']
      }, { // 樣式處理
        test: /\.less/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2, // 讓less文件裏引入的其餘文件也通過後面兩個loader處理
              // modules: true, // css模塊化(css文件只在當前模塊有效)
            }
          },
          'postcss-loader',
          'less-loader'
        ]
      }, {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ // 根據模板html, 生成新html文件
      template: 'src/index.html'
    }),
    new CleanWebpackPlugin({ // 清除文件夾
      dry: false
    })
  ]
};
複製代碼
  • webpack.prod.js:生產環境配置
const webpackMerge = require('webpack-merge'); // 合併webpack配置文件
const commonConfig = require('./webpack.comm');

const prodConfig = {
  mode: 'production', // 打包環境
  // development:cheap-module-eval-source-map(推薦)
  // production:cheap-module-source-map(推薦)
  devtool: 'none', // 設置源文件與打包文件的映射關係
};

module.exports = webpackMerge(commonConfig, prodConfig);
複製代碼
  • webpack.dev.js:開發模式配置
const webpack = require('webpack');
const webpackMerge = require('webpack-merge'); // 合併webpack配置文件
const commonConfig = require('./webpack.comm');

const devConfig = {
  mode: 'development', // 打包環境
  // development:cheap-module-eval-source-map(推薦)
  // production:cheap-module-source-map(推薦)
  devtool: 'cheap-module-eval-source-map', // 設置源文件與打包文件的映射關係
  devServer: { // 設置開發服務
    contentBase: './dist', // 根目錄
    open: true, // 自動打開瀏覽器
    port: 8080, // 端口號
    hot: true, // 開啓HMR
    hotOnly: true, // 不更新瀏覽器
    proxy: { // 設置接口代理(解決跨域)
      '/api': 'https://localhost:3000'
    }
  },
  optimization: {
    usedExports: true, // 打包被引用的模塊
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
};

module.exports = webpackMerge(commonConfig, devConfig);
複製代碼
  • package.json修改
"scripts": {
    "start": "webpack-dev-server --config ./build/webpack.dev.js",
    "build": "webpack --config ./build/webpack.prod.js",
    "server": "node server.js"
  },
複製代碼

Code Splitting進行代碼分割

將重複代碼抽離出來造成單獨的chunk,避免單個文件過大,而形成文件請求時間過長

同步代碼實現代碼分割,配置optimization項

optimization: {
    splitChunks: { // 代碼分割
      chunks: 'all', // 自動檢測應該分離的代碼
    }
  }
複製代碼

異步代碼實現代碼分割(import導入的模塊)

webpack會自動將異步代碼打包到單獨的文件中,但webpack在打包時,沒法識別動態異步引入語法,因此咱們須要安裝@babel/plugin-syntax-dynamic-import來支持動態異步引入語法

  • 安裝@babel/plugin-syntax-dynamic-import
# 支持動態異步引入模塊
npm install --save-dev @babel/plugin-syntax-dynamic-import --save-dev
複製代碼
  • 配置.babelrc文件
{
  "plugins": [
    "@babel/plugin-syntax-dynamic-import"
  ]
}
複製代碼

SplitChunksPugin配置參數

  • webpack默認配置項
splitChunks: {
    chunks: "async",
    minSize: 30000,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
        vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
        },
    default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}
複製代碼
  • 註釋版
splitChunks: {
      chunks: 'all', // 代碼分割目標:async(異步代碼) all(異步和同步代碼) initial(同步代碼)
      minSize: 30000, // 模塊size > minSize(30KB)進行代碼分割
      // maxSize: 50000, // 分割出的模塊size > maxSize(50KB)進行二次分割
      minChunks: 1, // 模塊使用次數 > minChunks進行代碼分割
      maxAsyncRequests: 5, // 異步模塊內部最大並行請求數
      maxInitialRequests: 3, // 入口並行加載的最大請求數(入口文件最多能拆分3個文件被http請求)
      automaticNameDelimiter: '~', // 文件名鏈接符
      name: true, // 自動生成文件名
      cacheGroups: { // 分割代碼緩存組(同步代碼分割有效)
        vendors: { // vendors組,入口文件:main.js
          test: /[\\/]node_modules[\\/]/, // 分割nodule_modules下的代碼
          priority: -10, // 分割優先級(當模塊符合多個組時,放在優先級高的組中)
          filename: 'vendors.js' // 打包文件名
        },
        default: { // default組,入口文件:main.js
          priority: -20,
          reuseExistingChunk: true, // 忽略已打包過的模塊
          filename: 'common.js'
        }
      }
    }
複製代碼

打包分析

info

  • 安裝 webpack-bundle-analyzer插件
npm install --save-dev webpack-bundle-analyzer
複製代碼
  • webpack中使用
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
};
複製代碼

Preloading

與核心js文件一塊兒下載(不推薦)

Prefetching(加快首屏渲染)

等待覈心js文件下載完畢,網絡帶寬空閒了,再去下載其餘模塊資源(推薦)

提取css

  • 安裝mini-css-extract-plugin
# 將css從js文件中抽離出來
npm install --save-dev mini-css-extract-plugin
複製代碼
  • 配置webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
     module: {
        rules: [{ // 樣式處理
        test: /\.(le|c)ss/,
        use: [
            {
            loader: MiniCssExtractPlugin.loader,
            options: {
                publicPath: '../', // 提取出來的css文件裏都會添加公共路徑
                hmr: process.env.NODE_ENV === 'development'
            }
        }, {
            loader: 'css-loader',
            options: {
                importLoaders: 2, // 讓less文件裏引入的其餘文件也通過後面兩個loader處理
                // modules: true, // css模塊化(css文件只在當前模塊有效)
            }
            },
            'postcss-loader',
            'less-loader'
        ]
    }]
  },
    plugins: [
        new MiniCssExtractPlugin({ // 抽離js文件裏的css
            filename: 'static/css/[name].[hash].css', // html直接引入的css文件
            chunkFilename: 'static/css/[id].[hash].css' // 間接引入的css文件
        })
  ],
};
複製代碼
  • 安裝optimize-css-assets-webpack-plugin
# 進行css壓縮
npm install --save-dev optimize-css-assets-webpack-plugin
複製代碼
  • 配置webpack.prod.js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
    optimization: {
        minimizer: [
            new OptimizeCSSAssetsPlugin({ // css代碼壓縮
            })
        ]
    }
};
複製代碼
相關文章
相關標籤/搜索