美文网首页
webpack下编写loader和plugin

webpack下编写loader和plugin

作者: 李牧敲代码 | 来源:发表于2020-04-28 17:05 被阅读0次

    【前言】

    本文的目的是对loader和plugin的编写有一个宏观的概念,具体的东西之后会增加。
    我们都知道loader(就是一个函数)是将不同的文件资源转换为js(将整个文件作为字符串传给loader,然后返回一个JS),插件是通过在监听webpack生命周期中的不同钩子去做一些事情,赋予webpack一些额外的能力。

    【本文目录】

    1. loader
    2. plugin

    loader

    举个例子:

    项目目录:

    QQ截图20200428155925.png

    我们的webpack配置文件可能是这样的:

    
    //webpack.config.js
    const path = require('path');
    
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MyPlugin = require('my-plugin');
    
    module.exports = {
        entry: ['./src/index.js'],
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        },
        mode:"development",
        module: {
            rules: [
                {
                    test: /\.txt$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: 'my-loader',
                            options: {
                                name: 'my-loader'
                            }
                        }
                    ]
                }
            ]
        },
        plugins: [
            new HtmlWebpackPlugin()
            new MyPlugin()
        ]
    }
    

    然后我们可以看到我对.txt文件使用了我自己的loader(my-loader)
    然后在当前的node_modeules下新建一个my-loader文件夹(为了能是webpack直接能找到),并通过npm init --y 初始化并新建一个index.js

    
    //index.js
    
    
    import { getOptions } from 'loader-utils';
    import validateOptions from 'schema-utils';
    
    // import path from 'path';
    
    // import memoryfs from 'memory-fs';
    
    // import webpack from 'webpack'
    
    
    
    const schema = {
        type: 'object',
        properties: {
            name: {
                type: 'string'
            }
        }
    }
    
    
    export default function loader(source) {
        // let callback = this.async();
        // const textpath = path.resolve(__dirname, 'test.txt');
    
        // this.addDependency(textpath);
    
        // fs
        // const options = getOptions(this);
    
        // fs.readFile(textpath, 'utf-8', function(err, data) {
        //     if(err) {
        //         return callback(err)
        //     }else {
        //         callback(null, `${data} \n ${source}`)
        //     }
        // })
    
    
    
        const options = loaderUtils.getOptions(this);
        validateOptions(schema, options, 'Example loader')
        source = {
            content: source.replace(/\[name\]/g, options.name)
        }
    
        return `export default ${JSON.stringify(source)}`
    }
    

    这里看到我参照官网用了babel,如果你没用babel,就用require好了。其中getOptions就是去拿我们平常传给loader的option的,schema-utils使用来校验option是否合法的。参数source就是我们要处理的文件整个的字符串形式。最后的return就是我们返回的JS(字符串).最后webpack会调用eval或者Function去执行这些字符串的.

    再来看下项目入口文件index.js的内容。

    
    //index.js
    
    const b = require('./test.txt').default
    
    console.log('b', b.content)
    

    最后在package.json下面新建一个script:"build":"webpack"

    {
      "name": "webpack-test",
      "version": "1.0.0",
      "description": "",
      "private": true,
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.9.0",
        "@babel/plugin-transform-runtime": "^7.9.0",
        "@babel/polyfill": "^7.8.7",
        "@babel/preset-env": "^7.9.5",
        "@babel/runtime": "^7.9.2",
        "babel-loader": "^8.1.0",
        "css-loader": "^3.5.3",
        "html-webpack-plugin": "^4.2.0",
        "style-loader": "^1.2.0",
        "webpack": "^4.43.0"
      }
    }
    
    
    

    然后运行npm run build
    最后用chrome打开dist目录下的index.html:


    QQ截图20200428165115.png

    看到了么?我将一个.txt文件转成了js,并最终使用!

    plugin

    plugin是一个构造函数,我们所有的工作就是在这个构造函数的原型上去定义一个一个apply方法,webpack调用插件的时候会去调用这个apply方法的。
    同样的按照loader的形式我们在项目根目录下的node_modules下新建一个my-plugin的文件夹,并在里面初始化npm并新建一个index.js文件。

    
    function MyPlugin () {
    
    }
    
    MyPlugin.prototype.apply = function (compiler) {
    
        compiler.plugin('done', function() {
            console.log('this is my plugin')
        })
    
    
    
    
        compiler.plugin('compilation', function(compilation) {
            compilation.plugin('optimize', function() {
                console.log("Assets are being optimized.");
            })       
        })
    
    
    
        compiler.plugin('emit', function(compilation, callbacks) {
    
    
            let fileList = 'in this build: \n'
            for (let fileName in compilation.assets) {
                fileList += '-' + fileName + '\n'
            }
    
            compilation.assets['filelist.md'] = {
                source: function() {
                    return fileList
                },
                size: function () {
                    return fileList.length
                }
            }
            callbacks();
    
        })
    
    }
    
    module.exports = MyPlugin;
    

    看到上面我调用了一系列的钩子了么?在每个钩子里我们可以拿到一些资源并做一些事情,这就是plugin的大致的原理。
    比如:
    我在'emit'这个钩子中生成了一个filelist.md的文件,记录了最终在经过webpack打包后所有文件的文件名列表。运行完npm run build后看下dist目录下的filelist.md文件:

    in this build: 
    -bundle.js
    -index.html
    

    看到没,我生成的2个文件都被记录了下来。

    【完】

    相关文章

      网友评论

          本文标题:webpack下编写loader和plugin

          本文链接:https://www.haomeiwen.com/subject/rftbwhtx.html