给webpack写个loader

何为loader

就是把一个文件读出来,然后根据自己的喜好各种操作字符串,但最终的字符串一定要是js代码,然后丢给webpack处理压缩打包。

例如vue-loader,是把文件组件里面改装成用Vue.component注册的组件,变成直接在html页面引入vue.js的开发模式的写法。

来写一个自己的loader

假设名为cn-loader,用来解析扩展名为.cn的文件

  • 第一步:先搭一个webpack项目,如下:

目录:

- loaders
  |- cn-loader.js //这个就是我们的loader
- public
  |- index.html  //html模板
- src
  |- index.cn //入口文件
  |- test-1.cn
  |- test-2.cn
- webpack.config.js
- package.json

package.json配置:

{
  "name": "loader",
  "version": "1.0.0",
  "description": "",
  "main": "index.cn",
  "scripts": {
    "start": "webpack-dev-server --mode development",
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@babel/preset-env": "^7.9.0",
    "babel-loader": "^8.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^4.0.3",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",
    "webpack-dev-server": "^3.10.3"
  }
}

webpack.config.js配置:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    module: {
        rules: [{
            test: /\.js$/,
            loader: 'babel-loader',
            options: {
                presets: ['@babel/preset-env']
            }
        },{
            test: /\.cn$/,
            use: './loaders/cn-loader.js',
            exclude: /node_modules/
        }]
    },
    resolve: {
        extensions: ['.js', '.cn']
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: './public/index.html'
        })
    ],
    stats: {
        modules: false
    }
}

好,项目基本就搭好了。

  • 第二步:假设我们用.cn文件来实现中文写代码

先看看test-1.cn:

导入:./test-2.cn 为:test2
打印:test2
变量:计数 = 100
函数:增加
    计数 = 计数 + 1
    打印:"计数的值为:" + 计数
    返回值:计数
执行:增加
导出:增加

没错,这是一段代码,它最终会被cn-loader解析成为:

import test2 from './test-2.cn'
console.log(test2)
var 计数 = 100
function 增加(){
    计数 = 计数 + 1
    console.log("计数的值为:" + 计数)
    return 计数
}
增加()
export default 增加

再看看简单的index.cn和test-2.cn
index.cn:

导入:./test-1.cn 为:test1
执行:test1

test-2.cn:

变量:哦嚯 = "哦嚯,这是test-2"
导出:哦嚯

注释:我们甚至可以js和中文混写
document.body.innerHTML = '<h1>cn-loader 是无敌的</h1>'

那么,关键的loader来了:

function parse(code){
    return code
    .replace(/导入[::]\s*(.+?)\s*(?:为[::]\s*(.+?))?(\n|$)/g, ($0, $1, $2) => {
        if($2 !== undefined){
            return 'import '+ $2 +' from "' +$1 + '";\n'
        }else{
            return 'import'+$1+';\n'
        }
    })
    .replace(/注释[::]/g, '//')
    .replace(/变量[::]\s*(.+?)(?:\s*=\s*(.+?))?(\n|$)/g, ($0, $1, $2) => {
        if($2 !== undefined){
            return 'var '+ $1 + '=' + $2 + ';\n'
        }
        return 'var '+$1+';\n';
    })
    .replace(/打印[::]\s*(.+?)(\n|$)/g, 'console.log($1)\n')
    .replace(/返回值[::]\s*(.+?)(\n|$)/g, 'return $1\n')
    .replace(/执行[::]\s*(.+?)(\n|$)/g, '$1()\n')
    .replace(/导出[::]\s*(.+?)(\n|$)/g, 'export default $1\n')
}
function parseFn(code){
    let lines = code.split(/\n/), fnStart = false
    for(let i=0; i<lines.length; i++){
        if(fnStart) {
            if(/^\s+/.test(lines[i])){
                continue
            }else{
                lines[i] = '}\n' + lines[i]
                fnStart = false
            }
        }
        if(!fnStart && /^函数[::]/.test(lines[i])){
            fnStart = true
            lines[i] = lines[i].replace(/^函数[::]\s*(.+?)\s*$/, 'function $1(){')
        }
    }
    return lines.join('\n')
}

//===== 华丽分隔线上部分是各种造作代码的逻辑: 就是把中文翻译成js=====
//===== 华丽分隔线下面这里就是这么回事,简单得要命================
module.exports = (code) => {
    // 一顿操作猛如虎
    code = parseFn(code)
    code = parse(code)
    // console.log(code)
    // 之后把操作好的东西给回webpack
    return code
}

顿时没什么神秘感,loader里module.exports 出去的函数,会被webpack在读取文件之后调用,并且会传来读取到的内容code。你只管对code操作,最后返回webpack认识的代码即可。

可能有人好奇文件的各种导入层级是不是要自己写递归?不是,导入导出的逻辑完全不用管,那是webpack基本的能力,你只管把它给你的每一份code解析成webpack认识的,webpack会根据我们给它的code中是否有import去递归找文件,一份一份输出code给我们操作。

现在是不是可以想得通.vue、.ts、tsx这些文件的loader了,脑瓜不疼了。

OK,撒花,鼓掌,各种夸!

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

推荐阅读更多精彩内容

  • 构建工具逐渐成为前端工程必备的工具,Grunt、Gulp、Fis、Webpack等等,译者有幸使用过Fis、Gul...
    陈坚生阅读 5,988评论 4 64
  • webpack使用学习 本分享学习借鉴webpack中文官网,官网链接(中文文档):https://www.web...
    腿毛怪丶叔叔阅读 865评论 0 5
  • webpack 是什么? 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(mo...
    IT老马阅读 3,301评论 2 27
  • 33、JS中的本地存储 把一些信息存储在当前浏览器指定域下的某一个地方(存储到物理硬盘中)1、不能跨浏览器传输:在...
    萌妹撒阅读 2,067评论 0 2
  • 人一生,有将近30多年的时间都需要工作,不是每个人都能找到令自己甘之如饴、为之奋斗的好工作。随着社会的高速发展,各...
    小胖子Miss_Li阅读 1,513评论 9 10