webpack4學習筆記(四)
前言
這是我花了幾個星期學習webpack4的學習筆記。內容不夠細,因為一些相對比較簡單的,就隨意帶過了。希望文章能給大家帶來幫助。如有錯誤,希望及時指出。例子都在learn-webpack
倉庫上。如果你從中有所收穫的話,希望你能給我的github
點個star
。
編寫loader
// index.js console.log('hello, atie')
配置webpack.config.js
// webpack.config.js module: { rules: [ { test: /\.js$/, include: /src/, loader: path.resolve(__dirname, './loaders/replaceLoader.js') } ] },
// 函式不能使用箭頭函式 module.exports = function(source) { console.log(source, 'source') return source.replace('atie', 'world') }
loader
檔案其實就是匯出一個函式,source
就是webpack
打包出的js
字串。這裡的loader
就是將上面的console.log('hello, atie')
替換為console.log('hello, world')
打包下程式碼,不出所料。控制檯就會打印出hello, world
當你想要給loader傳參時,可配置如下
module: { rules: [ { test: /\.js$/, include: /src/, use: [{ loader: path.resolve(__dirname, './loaders/replaceLoader.js'), options: { name: 'haha' } }] } ] },
通過給loader
新增options
這樣loader
中就可以通過this.query
獲取該引數了
module.exports = function(source) { // 控制檯輸出:console.log('hello atie') { name: 'haha' } source console.log(source, this.query, 'source') return source.replace('atie', 'world') }
當然變數不一定非要通過this.query
來獲取
可通過loader-utils
這個包來獲取傳入的變數
安裝:npm i loader-utils -D
const loaderUtils = require('loader-utils') // 函式不能使用箭頭函式 module.exports = function(source) { // console.log(source, this.query, 'source') const options = loaderUtils.getOptions(this) console.log(options, 'options') // { name: 'haha' } 'options' return source.replace('atie', 'world') }
打印出來的與上面this.query
一致
上面都是直接通過return
返回的,那麼我們還有沒有其他方法返回loader
翻譯後的程式碼呢?`
這裡就會用到callback
this.callback( err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any );
上面的程式碼就可以改寫成
module.exports = function(source) { const options = loaderUtils.getOptions(this) const result = source.replace('atie', options.name) this.callback(null, result) }
callback
優勢在於它可以傳遞多餘的引數
module.exports = function(source) { setTimeout(() => { return source.replace('atie', 'world') }, 1000) }
當我們把return
包到非同步方法裡,打包的時候就會報錯,那麼我們該怎麼辦呢?
這個時候就需要用到this.async()
module.exports = function(source) { const callback = this.async() setTimeout(() => { callback(null, source.replace('atie', 'world')) }, 2000) }
通過呼叫this.async()
返回的callback
方法來返回結果
use中的loader執行順序,先右後左,先下後上
編寫plugin
在根目錄下新建plugins
資料夾,並新建copyright-webpack-plugin.js
,內容如下:
class Copyright { constructor() { console.log('this is plugin') } apply(compiler) { } } module.exports = Copyright
注意:apply這個方法必須存在,不然外掛被執行的時候會報錯。
配置webpack.config.js
,如下:
const Copyrgiht = require('./plugins/copyright-webpack-plugin.js') ... plugins: [ new Copyrgiht() ]
執行下打包命令後
this is plugin Hash: 479baeba2207182096f8 Version: webpack 4.30.0 Time: 615ms Built at: 2019-05-08 23:05:08 AssetSizeChunksChunk Names bundle.js3.77 KiBmain[emitted]main index.html182 bytes[emitted]
控制檯打印出了this is plugin
接下來,我們繼續探索外掛的奧祕
在使用外掛的時候還可以傳參
// webpack.config.js plugins: [ new Copyrgiht({ name: 'atie' }) ]
class Copyright { constructor(options) { // console.log(options, 'this is plugin') this.options = options } apply(compiler) { console.log(this.options) } }
執行下打包命令:
{ name: 'atie' } Hash: 479baeba2207182096f8 Version: webpack 4.30.0 Time: 742ms Built at: 2019-05-08 23:24:10 AssetSizeChunksChunk Names bundle.js3.77 KiBmain[emitted]main index.html182 bytes[emitted]
控制就會輸出{name: 'atie'}
webpack
在呼叫apply
會傳遞一個compiler
引數,這個引數可以做很多事情,具體可以參考webpack
官網
這裡介紹下鉤子
class Copyright { apply(compiler) { compiler.hooks.emit.tapAsync('Copyright', (compilation,callback) => { console.log(compilation.assets, '以具有延遲的非同步方式觸及 run 鉤子。'); compilation.assets['copyright.txt'] = { source: function() { return 'copyright by atie' }, size: function() { return 17 } } callback() }) } } module.exports = Copyright
該鉤子是在檔案生成前觸發的。我們在檔案生成前,在asset
物件上在加一個檔案物件
打包之後
. ├── bundle.js ├── copyright.txt └── index.html
可以看到多了一個copyright.txt
,也就是我們上面建立的檔案。點開該檔案還會看到裡面的內容正是copyright by atie