這是我花了幾個星期學習webpack4的學習筆記。內容不夠細,由於一些相對比較簡單的,就隨意帶過了。但願文章能給你們帶來幫助。若有錯誤,但願及時指出。例子都在learn-webpack倉庫上。若是你從中有所收穫的話,但願你能給個人github
點個star
。javascript
// index.js console.log('hello, atie')
配置webpack.config.js
html
// 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')
java
打包下代碼,不出所料。控制檯就會打印出hello, world
webpack
當你想要給loader傳參時,可配置以下git
module: { rules: [ { test: /\.js$/, include: /src/, use: [{ loader: path.resolve(__dirname, './loaders/replaceLoader.js'), options: { name: 'haha' } }] } ] },
經過給loader
添加options
github
這樣loader
中就能夠經過this.query
獲取該參數了web
module.exports = function(source) { // 控制檯輸出:console.log('hello atie') { name: 'haha' } source console.log(source, this.query, 'source') return source.replace('atie', 'world') }
固然變量不必定非要經過this.query
來獲取npm
可經過loader-utils
這個包來獲取傳入的變量app
安裝: 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執行順序,先右後左,先下後上
在根目錄下新建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 Asset Size Chunks Chunk Names bundle.js 3.77 KiB main [emitted] main index.html 182 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 Asset Size Chunks Chunk Names bundle.js 3.77 KiB main [emitted] main index.html 182 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