簡單來說loader是讓其他類型的文件轉換成webpack能理解的js代碼的一段代碼(函數)
Out of the box, webpack only understands JavaScript files. Loaders allow webpack to process other types of files and converting them into valid modules that can be consumed by your application and added to the dependency graph.、
在你的應用程序中,有三種使用 loader 的方式:
- 配置(推薦):在 webpack.config.js 文件中指定 loader。
- 內聯:在每個 import 語句中顯式指定 loader。
- CLI:在 shell 命令中指定它們。
配置
module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] }
內聯
import Styles from 'style-loader!css-loader?modules!./styles.css';
選項可以傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}。
CLI
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
會對 .jade 文件使用 jade-loader,對 .css 文件使用 style-loader 和 css-loader。
那么如何編寫一個webpack-loader呢?
官方指南,下面就帶你一起手寫一個webpack-loader?
需求如下:
我們要寫一個對txt文件中的[name]替換成17,非常簡單.如下:
//src/loader.js const {getOptions} = require('loader-utils') module.exports = function (source){ const options = getOptions(this); console.log(source); source = source.replace(/\[name\]/g, options.name); console.log(source); return `export default ${JSON.stringify(source)}` }
//webpack.config.js配置 const path = require('path') module.exports = { mode:'development', context: __dirname, entry: `./src/test.txt`, output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.txt' }, module: { rules: [ { test: /\.txt$/, use: [ { loader: path.resolve(__dirname, './src/bar-loader.js'), options: { name: '18hahaha' } }, { loader: path.resolve(__dirname, './src/loader.js'), options: { name: '17' } } ] } ] } }
那么如何編寫一個loader與現有的loader一起使用呢?
接着寫:
//src/bar-loader.js const { getOptions } = require('loader-utils') module.exports = function (source) { const options = getOptions(this); console.log(11111,source); source = source.replace(/17/g, options.name); console.log(11111, source); return `export default ${JSON.stringify(source)}` }
//webpack.config.js rules: [ { test: /\.txt$/, use: [ { loader: path.resolve(__dirname, './src/bar-loader.js'), options: { name: '18hahaha' } }, { loader: path.resolve(__dirname, './src/loader.js'), options: { name: '17' } } ] } ]
還可以使用異步模式(async mode)
調用 this.async()來獲取this.callback()方法,然后在異步調用的回調函數中通過callback返回null以及處理結果。
module.exports = function(content) { var callback = this.async(); if(!callback) return someSyncOperation(content); someAsyncOperation(content, function(err, result) { if(err) return callback(err); callback(null, result); }); };
那么如何編寫一個loader的單元測試呢?OK.直接上代碼
編寫一個compiler.js
import path from 'path' import webpack from 'webpack' import memoryfs from 'memory-fs' export default (fixture, options = {}) => { const compiler = webpack({ context: __dirname, entry: `./${fixture}`, output: { path: path.resolve(__dirname), filename: 'bundle.js' }, module:{ rules:[ { test: /\.txt$/, use: { loader: path.resolve(__dirname, '../loaders/loader.js'), options: { name: '17' } } } ] } }) compiler.outputFileSystem = new memoryfs(); return new Promise((resolve, reject) => { compiler.run((err, stats) => { if(err) reject(err) resolve(stats) }) }) }
這樣就可以測試了
import compiler from './compiler.js'; test('Inserts name and outputs JavaScript', async () => { const stats = await compiler('example.txt'); // console.log(stats.toJson()); const output = stats.toJson().modules[0].source; expect(output).toBe(`export default "Hey 17!\\n"`); });
好了,demo寫完了,剩下就是根據需求編寫了.
最后奉上
loader API、官網的
loaders.