Loaders

40 阅读1分钟

上文asset module常用来导入一些图片、字体、文本类文件数据,而有一些需要解析处理的文件比如css, sass, ts等文件,单纯通过asset module是解决不了的,这时候就得利用 webpack loader的能力

处理CSS

写一个渲染button的类组件,src的文件结构如下:

src
    - components
        - say-hello-botton
            - index.js
            - say-hello-button.css
    - index.js

src/say-hello-botton/index.js的内容如下:

import './say-hello-button.css';

class SayHelloButton {
    render() {
        const button = document.createElement('button');
        button.innerHTML = 'Say Hello';
        button.classList.add("say-hello-button");
        const body = document.querySelector('body');
        button.onclick = function () {
            const p = document.createElement('p');
            p.innerHTML = 'Hello!';
            p.classList.add('hello-text');
            body.appendChild(p);
        }
        body.appendChild(button);
    }
}

export default SayHelloButton;

src/say-hello-botton/say-hello-button.css的内容如下:

.say-hello-button {
    font-size: 20px;
    padding: 7px 15px;
    color: white;
    background-color: goldenrod;
}

.hello-text {
    color: green;
    font-weight: bold;
}

src/index.js引入并渲染button:

import SayHelloButton from "./components/say-hello-button";

const sayHelloButton = new SayHelloButton();
sayHelloButton.render();

接下来告诉webpack如何处理css文件,这时候要用到loader:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist') ,
        publicPath: 'dist/'
    },
    mode: 'none',
    module: {
        rules: [
            {
                test: /\.(png|jpg|jpeg)/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 3 * 1024 // 3kb
                    }
                }
            },
            {
                test: /\.txt/,
                type: 'asset/source'
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader', 'css-loader'
                ]
            }
        ]
    }
}

值得注意的是use属性的列表中有两个loader,style-loader, css-loaderloaders的处理可以理解成一串工作流程,每一个loader都有自己的功能。以css处理为例,css-loader仅仅是读取文件内容,style-loader是将css的内容写入到bundle.js文件中(loader的处理是从后向前的)

到这里还没有结束,因为loader的处理能力并不是webpack原生的,对比assets module配置时,我们并没有引入其他的npm包,而如果是loader的处理,是需要额外引入使用到的loader:

npm install css-loader style-loader --save-dev

这时候打包,会发现按钮的样式已经成功展示,而样式表是写在bundle.js中的(后面在Plugins的讲解中会有如何拆分样式文件的内容)

处理SASS

将刚才的css文件改成scss后缀,然后可以尝试使用一些sass的特性,比如变量:

$font-size: 20px;
$background-color: goldenrod;

.say-hello-button {
    font-size: $font-size;
    padding: 7px 15px;
    color: white;
    background-color: $background-color;
}

.hello-text {
    color: green;
    font-weight: bold;
}

然后仿照css文件Loader的处理方式,在配置文件里拓展写sass的配置

{
    test: /\.scss$/,
    use: [
        'style-loader', 'css-loader', 'sass-loader'
    ]
}

别忘了要下载相应的loadersass处理器

npm install sass-loader sass  --save-dev

使用Babel

babel可以使ES6+的代码编译成ES5的代码以便兼容更多浏览器,在webpack中使用的配置如下

    {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ['@babel/env']
            }
        }
    }

其需要加载的npm包:

npm install @babel/core babel-loader @babel/perset-env

其中@babel/core是编译内核。@babel/perset-env是一个编译标准,随着其版本的升级,这个标准或者说范围是动态变化的,也就是说@babel/perset-env会慢慢兼容更新的ES特性。

较新的JS特性

如果当前版本的 @babel/perset-env 无法兼容某个ES特性该如何拓展呢?可以通过插件的形成拓展:

 {
    test: /\.js$/,
    exclude: /node_modules/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['@babel/env'],
            plugins: ['@babel/plugin-proposal-class-properties']
        }
    }
}

这仅仅是一个例子,因为当前的@babel/env已经兼容了“class自己有属性”的特性,为了有新的还未被兼容的ES特性,可以去babel官网找到对应的插件进行拓展