webpack下编写loader和plugin

【前言】

本文的目的是对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(直接package.jsontype字段使用moduloe也可以),如果你没用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个文件都被记录了下来。

【完】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • 编写 Loader Loader就像是一个翻译员,能把源文件经过转化后输出新的结果,并且一个文件还可以链式的经过多...
    oWSQo阅读 7,588评论 0 8
  • 可以结合慕课网的视频来读这篇文章,地址:http://www.imooc.com/learn/802 Webpac...
    哈哈腾飞阅读 1,880评论 0 7
  • Webpack学习总结 此文只是自己学习webpack的一些总结,方便自己查阅,阅读不变,非常抱歉!! 下载安装:...
    Lxs_597阅读 948评论 0 0
  • 全局安装webpack 全局安装webpack会有个问题,就是当你有两个项目依赖于不同版本的webpack,就会有...
    説好的妹紙呢阅读 1,816评论 0 11
  • 风停 雨静 那山谷里的云烟 徐徐的缠着散落的点点人家 许是这云雾与炊烟的暧昧 让人破不开眼前的虚无 解不开心中的迷...
    易安Yann阅读 95评论 0 0