Webpack4.x的四個核心概念介紹
一. 概念
需要理解四個核心概念:
- 入口(entry)
- 輸出(output)
- loader
- 插件(plugins)
1. 入口
1.1 基礎(chǔ)概念
指定 webpack 由哪個模塊作為項目構(gòu)建的開始。
通過配置 entry
屬性,指定一個或多個起點,默認值 ./src
:
module.exports = { entry: './path/leo/file.js' };
1.2 單文件入口
用法:entry: string|Array
當(dāng) entry
中沒有配置入口的文件對象的名稱,默認使用的是 main
名稱,輸出就是 main.js
,即:
// 默認情況 module.exports = { entry: './path/leo/file.js' }; // 配置單個入口 const config = { entry: { main: './path/leo/file.js' } };
可以看出,實際上 默認情況 只是 配置單個入口 的簡寫形式。
另外,文件路徑我們也可以傳入一個數(shù)組,就會將多個依賴文件一起注入:
const config = { entry: { main: ['./path/leo/file.js', './path/leo/index.js', './path/leo/server.js'] } };
1.3 多文件入口
用法:entry: {[entryChunkName: string]: string|Array}
多個文件完全分離,互相獨立(每個 bundle 中都有一個 webpack 引導(dǎo)(bootstrap)),常見于只有一個入口的單頁面應(yīng)用。
const config = { entry: { app: './src/app.js', vendors: './src/vendors.js' } };
2. 出口
2.1 基礎(chǔ)概念
指定 webpack 最終輸出的文件輸出位置和文件名等信息。
通過配置 output
屬性,指定輸出位置和文件名,默認輸出位置為 ./dist
:
兩個屬性:
path
:輸出的目錄絕對路徑;filename
:輸出的文件名稱;
const path = require('path'); module.exports = { entry: './path/leo/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'leo-webpack.bundle.js' } };
2.2 使用占位符來為每個文件命名,保證名稱唯一
output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js' }
2.3 使用CDN和資源hash
output: { path: "/home/proj/cdn/assets/[hash]", publicPath: "http://cdn.example.com/assets/[hash]/" }
如果編譯時不知道最終文件的 publicPath ,可以留空,并在入口文件中動態(tài)設(shè)置。或者在入口起點設(shè)置 __webpack_public_path__ 來忽略它。
__webpack_public_path__ = myRuntimePublicPath
3. loader
3.1 基礎(chǔ)概念
讓 webpack 能夠處理非 JS 文件,在 import
或 “加載”模塊時預(yù)處理文件。
通過配置 loader 兩個屬性來實現(xiàn):
test
屬性,用來標識出應(yīng)該被對應(yīng)的 loader 進行轉(zhuǎn)換的某個或多個文件;use
屬性,表示轉(zhuǎn)換時要用哪個 loader;
const path = require('path'); const config = { output: { filename: 'leo-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] } }; module.exports = config;
3.2 安裝并使用loader
如安裝一個 css-loader
和 ts-loader
使得 webpack 可以加載 CSS 文件,或者將 TypeScript
轉(zhuǎn)換成 JavaScript
:
npm install --save-dev css-loader ts-loader
使用:
// webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' }, { test: /\.ts$/, use: 'ts-loader' } ] } };
3.3 使用loader的三種方式
- 配置(推薦):在 webpack.config.js 文件中指定 loader。
指定多個loader:
module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] }
- 內(nèi)聯(lián):在每個 import 語句中顯式指定 loader。
可以在 import
語句或任何等效于 import
的方式中指定 loader,使用 !
將多個 loader 分開,每個部分都是相對于當(dāng)前目錄的解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
盡可能使用 module.rules,減少代碼量,并且在出錯時,更快地調(diào)試和定位 loader 中的問題。
- CLI:在 shell 命令中指定它們。
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
3.4 loader加載順序
loader 會從數(shù)組最后一個開始,往前一個一個加載:
// webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, ] } };
3.5 loader 特性
- loader 支持鏈式傳遞。
- 能夠?qū)Y源使用流水線(pipeline)。一組鏈式的 loader 將按照相反的順序執(zhí)行。loader 鏈中的第一個 loader 返回值給下一個 loader。在最后一個 loader,返回 webpack 所預(yù)期的 JavaScript。
- loader 可以是同步的,也可以是異步的。
- loader 運行在 Node.js 中,并且能夠執(zhí)行任何可能的操作。
- loader 接收查詢參數(shù)。用于對 loader 傳遞配置。
- loader 也能夠使用 options 對象進行配置。
- 除了使用 package.json 常見的 main 屬性,還可以將普通的 npm 模塊導(dǎo)出為 loader,做法是在 package.json 里定義一個 loader 字段。
- 插件(plugin)可以為 loader 帶來更多特性。
- loader 能夠產(chǎn)生額外的任意文件。
4. 插件
4.1 基礎(chǔ)概念
讓 webpack 能夠執(zhí)行更多任務(wù),從優(yōu)化和壓縮,到重新定義環(huán)境中的變量,非常強大。
插件目的在于解決 loader 無法實現(xiàn)的其他事。
使用時,只需要 require
它,并添加到 plugins
數(shù)組,通過 new
實例化即可:
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝 const webpack = require('webpack'); // 用于訪問內(nèi)置插件 const config = { module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] }, plugins: [ new HtmlWebpackPlugin({template: './src/index.html'}) ]}; module.exports = config;
4.2 核心知識
原理剖析:
webpack 插件是一個具有 apply
屬性的 JavaScript 對象。apply
屬性會被 webpack compiler
調(diào)用,并且 compiler
對象可在整個編譯生命周期訪問。
用法:
由于插件可以攜帶參數(shù)/選項,你必須在 webpack
配置中,向 plugins
屬性傳入 new
實例。
配置:
// webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); //通過 npm 安裝 const webpack = require('webpack'); //訪問內(nèi)置的插件 const path = require('path'); const config = { entry: './path/leo/file.js', output: { filename: 'my-first-webpack.bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.(js|jsx)$/, use: 'babel-loader' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
5. 模式
通過配置 mode
參數(shù),指定當(dāng)前的開發(fā)模式,有 development
和 production
兩個值:
module.exports = { mode: 'production' };
也可以通過 CLI 參數(shù)傳遞:
webpack --mode=production
參數(shù)描述:
選項 | 描述 |
---|---|
development | 會將 process.env.NODE_ENV 的值設(shè)為development。啟用 NamedChunksPlugin和 NamedModulesPlugin。 |
production | 會將 process.env.NODE_ENV 的值設(shè)為 production。啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin,OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。 |
記住,只設(shè)置 NODE_ENV,則不會自動設(shè)置 mode。
二. 配置
webpack 的配置文件,是導(dǎo)出一個對象的 JavaScript 文件,由 webpack 根據(jù)對象定義的屬性進行解析。
因為 webpack 配置是標準的 Node.js CommonJS 模塊,你可以做到以下事情:
- 通過
require(...)
導(dǎo)入其他文件; - 通過
require(...)
使用npm
的工具函數(shù); - 使用 JavaScript 控制流表達式,例如
?:
操作符; - 對常用值使用常量或變量;
- 編寫并執(zhí)行函數(shù)來生成部分配置;
但應(yīng)避免以下做法:
- 在使用 webpack 命令行接口(CLI)(應(yīng)該編寫自己的命令行接口(CLI),或使用
--env
)時,訪問命令行接口(CLI)參數(shù); - 導(dǎo)出不確定的值(調(diào)用 webpack 兩次應(yīng)該產(chǎn)生同樣的輸出文件);
- 編寫很長的配置(應(yīng)該將配置拆分為多個文件);
1. 基本配置
// webpack.config.js var path = require('path'); module.exports = { mode: 'development', entry: './foo.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'foo.bundle.js' } };
2. 多種配置
除了到處單個配置對象,我們也可以有一些其他方式:
2.1 導(dǎo)出為一個函數(shù)
我們可能需要同時考慮到開發(fā)環(huán)境和生產(chǎn)環(huán)境,在 webpack.config.js
中實現(xiàn),我們會有至少兩種方式:
- 導(dǎo)出一個配置對象來代替;
- 導(dǎo)出一個可以傳入?yún)?shù)的函數(shù):
傳入兩個參數(shù):環(huán)境變量(查看 CLI 文檔的環(huán)境選項)和 map 對象(argv
)參數(shù)。
module.exports = function(env, argv) { return { mode: env.production ? 'production' : 'development', devtool: env.production ? 'source-maps' : 'eval', plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: argv['optimize-minimize'] // 只有傳入 -p 或 --optimize-minimize }) ] }; };
2.2 導(dǎo)出為一個 Promise
webpack 將運行由配置文件導(dǎo)出的函數(shù),并且等待 Promise
返回。便于需要異步地加載所需的配置變量。
module.exports = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ entry: './app.js', /* ... */ }) }, 5000) }) }
2.3 導(dǎo)出多個配置對象
我們把導(dǎo)出對象設(shè)置成一個數(shù)組,webpack 運行時,會將所有配置對象都構(gòu)建,這對于針對多個構(gòu)建目標(例如 AMD 和 CommonJS)打包一個 library非常有用。
module.exports = [{ output: { filename: './dist-amd.js', libraryTarget: 'amd' }, entry: './app.js', mode: 'production', }, { output: { filename: './dist-commonjs.js', libraryTarget: 'commonjs' }, entry: './app.js', mode: 'production', }]
3. 使用其他配置語言
webpack 接受以多種編程和數(shù)據(jù)語言編寫的配置文件。支持的文件擴展名列表,可以在 node-interpret 包中找到。使用 node-interpret,webpack 可以處理許多不同類型的配置文件。
文檔介紹:《使用不同語言進行配置(configuration languages)》
3.1 TypeScript
為了用 TypeScript 書寫 webpack 的配置文件,必須先安裝相關(guān)依賴:
npm install --save-dev typescript ts-node @types/node @types/webpack
使用 TypeScript 書寫 webpack 的配置文件:
// webpack.config.ts import path from 'path'; import webpack from 'webpack'; const config: webpack.Configuration = { mode: 'production', entry: './foo.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'foo.bundle.js' } }; export default config;
3.2 Babel and JSX
在以下的例子中,使用了 JSX
(React
形式的 javascript)以及 Babel
來創(chuàng)建 JSON
形式的 webpack 配置文件:
首先安裝依賴:
npm install --save-dev babel-register jsxobj babel-preset-es2015
設(shè)置配置:
// .babelrc { "presets": [ "es2015" ] } // webpack.config.babel.js import jsxobj from 'jsxobj'; // example of an imported plugin const CustomPlugin = config => ({ ...config, name: 'custom-plugin' }); export default ( );
三. 模塊
1. 模塊介紹
開發(fā)中將程序分解成離散功能塊,成為模塊。
而 webpack 模塊能夠以各種形式表達他們的依賴關(guān)系:
- es6:
import
語句; - CommonJS:
require()
語句; - AMD:
define
和require
語句; css/sass/less
文件中的@import
語句;- 樣式(
url(...)
)或 HTML 文件中的圖片鏈接(image url
);
查看更多 模塊方法。
2. 模塊解析
使用 resolver
庫來找到模塊的絕對路徑,幫助 webpack 找到 bundle 中需要引入的模塊代碼,這些代碼包含在每個 require
/ import
語句中,在模塊打包中,webpack 使用 enhanced-resolve 來解析文件路徑
webpack 解析規(guī)則: 使用 enhanced-resolve
,webpack
支持解析三種文件路徑:
- 絕對路徑:
import "/home/me/file"; import "C:\\Users\\me\\file";
- 相對路徑:
import "../src/file1"; import "./file2";
- 模塊路徑:
import "module"; import "module/lib/file";
模塊將在 resolve.modules
中指定的所有目錄中搜索,另外可以使用 resolve.alias
做初始化模塊路徑。
解析器(resolver)檢查路徑是否指向文件或目錄,如果是指向文件:
- 如果有文件拓展名則直接打包;
- 否則使用 [
resolve.extensions
] 選項作為文件擴展名來解析,配置解析器在解析中能夠接受哪些擴展名(例如.js
,.jsx
)。
如果是指向文件夾,則按照步驟找到正確拓展名的文件:
- 如果文件夾中包含
package.json
文件,則按照順序查找 resolve.mainFields 配置選項中指定的字段。并且package.json
中的第一個這樣的字段確定文件路徑。 - 如果不存在
package.json
文件或者package.json
文件中的main
字段沒有返回一個有效路徑,則按照順序查找resolve.mainFiles
配置選項中指定的文件名,看是否能在import/require
目錄下匹配到一個存在的文件名。 - 文件擴展名通過
resolve.extensions
選項采用類似的方法進行解析。
3. 解析 loader
Loader 解析遵循與文件解析器指定的規(guī)則相同的規(guī)則。但是 resolveLoader
配置選項可以用來為 Loader 提供獨立的解析規(guī)則。
4. 緩存
每個文件系統(tǒng)訪問都被緩存,以便更快觸發(fā)對同一文件的多個并行或串行請求。在觀察模式下,只有修改過的文件會從緩存中摘出。如果關(guān)閉觀察模式,在每次編譯前清理緩存。
有關(guān)上述配置的更多信息,請查看解析 API學(xué)習(xí)。
四. 構(gòu)建目標
注意:webpack 的 target
屬性不要和output.libraryTarget
屬性混淆。
1. 用法
在你的 webpack 配置中設(shè)置 target
的值:
module.exports = { target: 'node' };
在上面例子中,使用 node
webpack 會編譯為用于「類 Node.js」環(huán)境(使用 Node.js 的 require
,而不是使用任意內(nèi)置模塊(如 fs
或 path
)來加載 chunk)。
更多詳細的值,可以參考 構(gòu)建目標(targets)
2. 多個 target
盡管 webpack 不支持向 target
傳入多個字符串,你可以通過打包兩份分離的配置來創(chuàng)建同構(gòu)的庫:
var path = require('path'); var serverConfig = { target: 'node', output: { path: path.resolve(__dirname, 'dist'), filename: 'lib.node.js' } //… }; var clientConfig = { target: 'web', // <=== 默認是 'web',可省略 output: { path: path.resolve(__dirname, 'dist'), filename: 'lib.js' } //… }; module.exports = [ serverConfig, clientConfig ];
到此這篇關(guān)于Webpack核心概念的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
用JavaScript獲取頁面文檔內(nèi)容的實現(xiàn)代碼
下面小編就為大家?guī)硪黄肑avaScript獲取頁面文檔內(nèi)容的實現(xiàn)代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06javascript設(shè)計模式 – 訪問者模式原理與用法實例分析
這篇文章主要介紹了javascript設(shè)計模式 – 訪問者模式,結(jié)合實例形式分析了javascript訪問者模式基本概念、原理、用法及操作注意事項,需要的朋友可以參考下2020-04-04javascript使用isNaN()函數(shù)判斷變量是否為數(shù)字
javascript中判斷變量是否為數(shù)字的方法,這里主要介紹javascript里的 isNaN() 函數(shù),具體使用如下,感興趣的朋友可以參考下2013-09-09?js中toString()函數(shù)與valueOf()函數(shù)使用與區(qū)別
在等于運算符中,如果比較的內(nèi)容包含對象類型數(shù)據(jù),則會涉及隱式轉(zhuǎn)換,那么就會調(diào)用toString()函數(shù)和valueOf()函數(shù),本文主要介紹了?js中toString()函數(shù)與valueOf()函數(shù)使用與區(qū)別,感興趣的可以了解一下2022-04-04