之前在上卷中,我主要梳理了 webpack 入門知識,在此我將更接近於工程中的知識實際梳理一遍
本文持續更新中...
前置知識:Webpack 實戰:入門、進階與調優(上卷)
前處理器(loader)
loader 概述
- 每一個 loader 本質上都是一個函式,在 webpack4 之前,loader 函式的輸入輸出都必須為字串,但在 webpack4 之後,loader 也同時支援 抽象語法樹(AST) 的傳遞,以此來減少程式碼的重複解析
用公式可以表示為:output = loader(input)
- 在此,我們來看一下 loader 的原始碼結構,以此闡釋 loader 是如何工作的:
module.exports = function loader (content, map, meta) { var callback = this.async(); var result = handler(content, map, meta); callback{ null, // error result.content, // 轉換後的內容 result.map, // 轉換後的 source-map result.meta, // 轉換後的 AST }; };
從程式碼中可以看出,loader 本身就是一個函式,將函式中接收到的內容進行轉換,然後返回轉換後的結果
(可能包含 sourcr map 和 AST 物件)
loader 的配置
- webpack 只認識 JavaScript,對於其他型別的資源,比如 CSS、圖片等等,必須預先定義一個或多個 loader 來進行轉譯,經過 loader 輸出為 webpack 能夠接受的形式再繼續進行
因此,loader 做的實際上是一個預處理的工作 - loader 的引入:
- 假設在我們的目錄中,有以下兩種檔案:
|-app.js |-style.css
- 我們要做的是將 css 檔案引入到 js 檔案中使用,那麼跟著我開始吧!
- 安裝第三方模組
- webpack 本身並不含有任何的 loader,而所有的 loader 都是第三方 npm 模組,所以我們必須先安裝它
npm install --save-dev css-loader
- webpack 本身並不含有任何的 loader,而所有的 loader 都是第三方 npm 模組,所以我們必須先安裝它
- 引入到工程中
- 在
webpack.config.js
中配置:module.exports = { // ... module: { rules: [{ test: /\.css$/, use: ['css-loader'], }], }, };
- 在
- 配置項的說明:
- module.rules 代表著模組的處理規則,每條規則都包含著許多配置項,這裡我們只用最重要的兩項:test 和 use
- test 接受一個正規表示式或者元素為正規表示式的陣列,如果匹配這條正規表示式,那麼就會使用與之對應的規則,比如這裡的
/\.css$/
用來匹配所有的.css
結尾的檔案 - use 接受一個陣列,陣列中包含著對應 test 會使用到的所有 loader,比如這裡的 css 檔案會使用到
css-loader
,如果只有一個 loader,那麼也可以省略陣列,只寫成字串
- 假設在我們的目錄中,有以下兩種檔案:
- 鏈式 loader:
- 上述的案例是不成功的,因為我們還差一樣東西:style-loader
- 每一個 loader 的功能都是獨特而侷限的,也就是說,一種型別的模組可以需要多種 loader 共同完成,在處理 css 檔案時同樣如此,需要
style-loader
和css-loader
共同完成 - 安裝
npm install --save-dev style-loader
- 新增配置
// webpack.config.js module.exports = { // ... module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'], }], }, };
在 webpack 打包時,是按照陣列從後往前的順序將資源交給 loader 處理的,因此要把最後生效的 style-loader 放在最前面
- exclude 與 include
- 在專案中我們經常會用到
babel-loader
來處理 ES6+ 語言特性,將其編譯為 ES5 來適應瀏覽器,但是對於 node_modules 中的 js 檔案來說,很多都是已經編譯為 ES5 的,因此沒必要再使用 babel-loader 來進行額外的處理 - exclude 與 include 就是用來排除規則的,他們可接收正規表示式或者字串(字串即檔案的絕對路徑),以及由他們組成的陣列,如:
rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /node_modules/, }],
- 這裡的含義是:對於匹配到正規表示式的模組,若在 exclude 指定的目錄中(此處為 node_modules 目錄),則不會執行該 use 規則
- 除了 exclude 之外,使用 include 配置也能達到相同的效果,如:
rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'], include: /src/, }],
- 值得注意的是,include 的邏輯似乎與 exclude 是相反的,對於匹配到正規表示式的模組,若在 include 指定的目錄中(此處為 src 目錄),才執行該 use 規則
- exclude 與 include 同時存在時,exclude 的優先順序更高,如:
rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /node_modules/, include: /node_modules\/awesome/, }]
- 此時,exclude 使得 node_modules 目錄已經被排除了,雖然 include 之後想要讓該 use 規則對 node_modules 中的某一個模組生效,也是無濟於事的,因為 include 是無法覆蓋 exclude 的
- 要實現原本的需求,我們可以改為:
rules: [{ test; /\.css/, use: ['style-loader', 'css-loader'], // 用 exclude 排除 node_modules 中除了 foo 和 bar 以外的所有模組 exclude: /node_modules\/(?!(foo|bar)\/).*/, }]
這令人頭疼的正則,哎,,Ծ^Ծ,,
- 另外,由於 exclude 的優先順序跟高,所以我們可以對 include 的子目錄進行排除,如:
rules: [{ test; /\.css/, use: ['style-loader', 'css-loader'], exclude: /src\/lib/, include: /src/, }]
此處的結果就是:該 use 規則只對 src 目錄生效,同時排除 src 目錄中的 lib 目錄
- 注:exclude 與 include 的配置項往往是必須考慮的,也是常加的,否則可能會拖慢整體的打包速度
- 在專案中我們經常會用到
- resource 與 issuer
- resource 與 issuer 可以用於更加精確地確定模組規則的作用範圍,如:
// index.js import './style.css'
在 webpack 中,被載入模組是 resource,而載入者是 issuer,在上面的例子中,resource 是
style.css
,載入者是index.js
。 - 前面介紹的 test、exclude、include 在本質上就是對 resource 的配置,如果想要對 issuer 增加條件的話,需要額外地寫配置,比如,我們只想讓
/src/pages
目錄下的 js 檔案可以引用 css,本質想就是改變載入者的範圍,配置如下:rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /node_modules/, issuer: { test: /\.js$/, include: /src/pages/, }, }], // 只有 /src/pages/ 下面的 js 檔案引用 css 檔案才能使此 use 規則生效
- 事實上,上述程式碼的可讀性較差,我們可以改為:
rules: [{ use: ['style-loader', 'css-loader'], resource: { test: /\.css$/, exclude: /node_modules/, }, issuer: { test: /\.js$/, exclude: /node_modules/, }, }],
注:此風格和上面的程式碼風格無法並存的,只能選擇一種風格配置
- 事實上,上述程式碼的可讀性較差,我們可以改為:
- resource 與 issuer 可以用於更加精確地確定模組規則的作用範圍,如:
- enforce
- webpack 中的 loader 按照執行順序可分為:pre、inline、normal、post四種,之前我們直接定義的 loader 都屬於 normal 型別,官方已不推薦 inline 形式,而 pre 和 post 形式則需我們使用 enforce 指定,如:
rules: [{ test: /\.css$/, enforce: 'pre', use: 'eslint-loader', // eslint-loader 的功能是對原始碼進行質量檢測,這種檢測工作往往在其他 loader 之前執行 }]
這段程式碼的解釋為:對於所有匹配正規表示式的模組,首先使用的 loader 規則就是 eslint-loader
- 概述起來就是,enforce 可以強制指定 loader 的執行順序
- pre 能強制 loader 首先執行
- post 能強制 loader 最後執行
- webpack 中的 loader 按照執行順序可分為:pre、inline、normal、post四種,之前我們直接定義的 loader 都屬於 normal 型別,官方已不推薦 inline 形式,而 pre 和 post 形式則需我們使用 enforce 指定,如:
- 常用 loader 介紹
- loader 官方文件
- 模板 loader:
- html-loader : 將HTML檔案匯出編譯為字串,可供js識別的其中一個模組
- pug-loader : 載入pug模板
- jade-loader : 載入jade模板(是pug的前身,由於商標問題改名為pug)
- ejs-loader : 載入ejs模板
- handlebars-loader : 將Handlebars模板轉移為HTML
- 樣式 loader:
- css-loader : 解析css檔案中程式碼
- style-loader : 將css模組作為樣式匯出到DOM中
- less-loader : 載入和轉義less檔案
- sass-loader : 載入和轉義sass/scss檔案
- postcss-loader : 使用postcss載入和轉義css/sss檔案
- 指令碼轉換編譯 loader:
- script-loader : 在全域性上下文中執行一次javascript檔案,不需要解析
- babel-loader : 載入ES6+ 程式碼後使用Babel轉義為ES5後瀏覽器才能解析
- typescript-loader : 載入Typescript指令碼檔案
- coffee-loader : 載入Coffeescript指令碼檔案
- JSON載入 loader:
- json-loader : 載入json檔案(預設包含)
- json5-loader : 載入和轉義JSON5檔案
- Files檔案 loader:
- raw-loader : 載入檔案原始內容(utf-8格式)
- url-loader : 多數用於載入圖片資源,超過檔案大小顯示則返回data URL
- file-loader : 將檔案傳送到輸出的資料夾並返回URL(相對路徑)
- jshint-loader : 檢查程式碼格式錯誤
- 載入框架 loader:
- vue-loader : 載入和轉義vue元件
- angualr2-template--loader : 載入和轉義angular元件
- react-hot-loader : 動態重新整理和轉義react元件中修改的部分,基於webpack-dev-server外掛需先安裝,然後在webpack.config.js中引用react-hot-loader
樣式處理
正在更新中...