手写实现webpack中的loader

1,237 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

回顾

loader可以把webpack除过js、json外不能解析的文件转换成webpack可以解析的文件,是一个解析器,翻译官。
一个loader只能干一件事情,并且是有顺序的。

使用loader

例如:webpack项目里要使用一个less文件,但是Webpack不支持,所以,需要使用loader
首先安装:
npm install style-less css-loader less less-loader
因为less-loader依赖于less所以也需要安装less,less-loader是把less转换成css,而css-loader是把css进行了序列化,处理添加到出口文件中,style-loader是把通过在html头部head里动态创建style 标签,把样式添加在里面,把序列化的css转换成样式。
然后在webpack.config.js里面进行配置loader,样式就可以成功显示了。
webpack.config.js:

const path = require("path");
module.exports = {
    // entry:'./src/other.js',
    entry: {
        index: './src/index.js',
        list: './src/list.js'
    },
    output: {
        filename: "[name].js",//利用占位符,文件名不要重复
        path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.css$/,
                use: ["style-loader","css-loader"]
            },
            {
                test: /.less$/,
                use: ["style-loader","css-loader","less-loader"]
            },
        ]
    }
}

注意配置里面的顺序,是自右向左的。
项目目录:

image.png 可以看一下重要的文件代码:
src/index.js :

import {add} from './other.js'
import css from "./index.css";
import test from "./test.less";
const json =require('./index.json')
console.log(json,add(1,2));
console.log('哈哈');

src/index.css:

body{
    background: red;
}

src/test.less:

body{
  div{
    background: blue;
  }
}

dist/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="index.js"></script>
</head>

<body>
  <div>这是个webpack项目</div>
</body>
</html>

配置文件webpack.config.js上面已经展示。 打开dist/index.html页面看下效果。

image.png

手写实现loader

现在我们实现上面三个loader,style-loader,css-loader,less-loader

手写less-loader

先实现less-loader:
myLoaders/test-less-loader:

const less = require('less');
module.exports = function (sourse) {
    less.render(sourse, (e, output) => {
        this.callback(e, output.css)
    })
}
 

这里工作机制是,项目运行时,看到less文件,然后就直接走到test-less-loader这个js文件里。然后这个js文件里面接受的参数就是less文件的内容。 这里其实就是把less转换成css返回了。
首先引入我们安装好的less,然后写一个导出的函数,这个函数接受的参数就是我们less文件里面的内容,然后用less自带的render编译器,进行传参数,第一个参数是要转化的less内容,第二个参数是一个函数,函数里的output.css就是转换后的css内容。
然后我们用this.callback把转换后的css返回。
想更加深入的了解less.render的或者less其他内容时,可去less官网 截取几个官网less.render的例子代码:

image.png

手写css-loader

再来实现css-loader:
myLoaders/test-css-loader:

module.exports=function(sourse){  
    console.log(sourse);
   return JSON.stringify(sourse);
}

这个也比较简单,代码很短,这里做的处理就只是把css代码序列化,用JSON.stringify就ok了,然后再导出的函数里面返回,因为css-loader本来做的事情就只有意见,把css代码序列化。

手写style-loader

最后再来实现style-loader:
style-loader做了一件事就是在html的头部head里动态创建style标签,然后把css样式放进去。 myLoaders/test-style-loader:

module.exports = function (sourse) {
    return `const ele=document.createElement('style');  
      ele.innerHTML=${sourse};
      document.head.appendChild(ele);`
}

这段代码就是做了上面说的事情。
最后别忘了要修改配置,之前引用的是人家官方的loader,现在都改成我们自己写的loader。
加了一行指向loader的本地文件夹:
image.png
分别指向的是,原本的node_modules,和我们创建的myLoaders模块。默认的是只指向node_modules模块。
这块也做修改,改成我们自己写的loader:

image.png
配置文件全部代码:
webpack.config.js:

const path = require("path");
module.exports = {
    // entry:'./src/other.js',
    entry: {
        index: './src/index.js',
        list: './src/list.js'
    },
    output: {
        filename: "[name].js",//利用占位符,文件名不要重复
        path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
    },
    mode: 'development',
    resolveLoader:{
        modules:['node_modules','myLoaders']
    },
    module: {
        rules: [
            {
                test: /.css$/,
                use: ["style-loader","css-loader"]
            },
            {
                test: /.less$/,
                use: ["test-style-loader","test-css-loader","test-less-loader"]
            },
            {
                test: /.sass$/,
                use: ["style-loader","css-loader","sass-loader"]
            },
        ]
    }
}

最后执行构建npm run...,重新打包,看下效果:
构建成功后,看下dist/index.js出口文件:

image.png
可以看到我们刚才自己的loader的代码,再看下dist/index.html的页面效果:

image.png
跟官方的loader效果一模一样,成功啦。

完结

以上我们就把手写style-loader,css-loader,less-loader,写完了,代码很短,也挺简单的,其实只要知道每个loader都干了一件什么事情,我们去实现这个是事情就好啦。