《Webpack5 核心原理与应用实践》学习笔记->处理CSS

382 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

直接根据上篇的案例继续编写,不要每次都新建一个demo了,上篇-> 掘金课程《Webpack5 核心原理与应用实践》学习笔记

如何借助预处理器、PostCSS 等构建现代 CSS 工程环境?

1. webpack 如何处理 css 资源?

原生webpack并不认识css,如果直接在.js文件中直接引入.css文件,会导致编译失败。

  • src下面新建一个index.css文件,里面随便写点代码。
// index.css
body {
    background: pink;
}
  • index.js文件里面引入index.css
// index.js
import './index.css'

const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
list.map(item => item)

虽然上节配置好了ts的环境,但是以后的课程如果没有一定指定ts就还是使用.js,这里只是学习webpackts准备这节完成再继续专精

  • 命令行:npx webpack ,可以看到会编译失败

image.png

2. webpack处理cssloader

  • webpack处理cssloader通常会用到如下:
    • css-loader:该 Loader 会将 CSS 等价翻译为形如 module.exports = "${css}" 的JavaScript 代码,使得 Webpack 能够如同处理 JS 代码一样解析 CSS 内容与资源依赖;
    • style-loader:该 Loader 将在产物中注入一系列 runtime 代码,这些代码会将 CSS 内容注入到页面的 <style> 标签,使得样式生效;
    • mini-css-extract-plugin:该插件会将 CSS 代码抽离到单独的 .css 文件,并将文件通过 <link> 标签方式插入到页面中。

当 Webpack 版本低于 5.0 时,请使用 extract-text-webpack-plugin 代替 mini-css-extract-plugin

3. 配置webpack

  • 安装依赖

    • 命令行:npm i -D css-loader style-loader
    • webpack.config.js添加配置
    const path = require('path');
    const EslintPlugin = require('eslint-webpack-plugin');
    
    module.exports = {
        mode: 'development',
        entry: {
            index: './src/index.js',
            test: './src/test.ts'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env', '@babel/preset-typescript']
                        }
                    }
                },
                {
                    test: /.ts$/,
                    use: {
                        loader: 'ts-loader'
                    }
                },
                // 处理css的loader
                {
                    test: /.css$/,
                    use: ['style-loader', 'css-loader'] // 这里css-loader需要写到后面
                }
            ]
        },
        resolve: {
            extensions: ['.ts', '.js'],
        },
        plugins: [
            new EslintPlugin({
                extensions: ['.ts', '.js']
            })
        ]
    }
    

    这里先用只有css-loaderstyle-loaderloader的加载顺序是从后往前,后面一个处理完成之后,会把结果抛给前面的loader再进行下一步的处理。
    css-loader只会把css放到.js文件中,不会对样式产生作用,所以需要style-loader进行下一步处理。
    style-loader会把css拿出来,然后创建<style>标签,并插入到<head>中。

    • 命令行:npx webpack
    • 这里编译成功后,可以看到没有.css结尾的文件,因为css生成在.js文件中了,感兴趣可以找找看。

    image.png

生产环境

上面将css放到.js文件中,无疑是会增加包的体积,这样会产生很多问题。

  1. cssjs并存,无法并行加载,只是在js线程中加载。

  2. 包体积变大,影响加载时间(可以分包解决)。

  3. cssjs随便一者发生修改,就会丢失浏览器缓存能力。

说白了就是影响首屏加载时间。
所以在生产环境中使用mini-css-extract-plugin代替style-loader

  • 安装mini-css-extract-plugin
    • 命令行:npm i -D mini-css-extract-plugin html-webpack-plugin

    mini-css-extract-plugin需要搭配html-webpack-plugin来使用,所以这里需要安装两个。

    • 配置webpack.config.js
    const path = require('path');
    const EslintPlugin = require('eslint-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 引入mini-css-extract-plugin
    const HTMLWebpackPlugin = require('html-webpack-plugin'); // 引入html-webpack-plugin
    
    module.exports = {
        mode: 'development',
        entry: {
            index: './src/index.js',
            test: './src/test.ts'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env', '@babel/preset-typescript']
                        }
                    }
                },
                {
                    test: /.ts$/,
                    use: {
                        loader: 'ts-loader'
                    }
                },
                {
                    test: /.css$/,
                    use: [
                        (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader) // 根据运行环境判断使用哪个loader
                        , 'css-loader'
                    ]
                }
            ]
        },
        resolve: {
            extensions: ['.ts', '.js'],
        },
        plugins: [
            new EslintPlugin({
                extensions: ['.ts', '.js']
            }),
            new MiniCssExtractPlugin(), // 使用MiniCssExtractPlugin
            new HTMLWebpackPlugin() // 使用HTMLWebpackPlugin
        ]
    }
    
    • mini-css-extract-plugin 库同时提供 Loader、Plugin 组件,需要同时使用
    • mini-css-extract-plugin 不能与 style-loader 混用,否则报错,所以上述示例中需要判断 process.env.NODE_ENV 环境变量决定使用那个 Loader
    • mini-css-extract-plugin 需要与 html-webpack-plugin 同时使用,才能将产物路径以 link 标签方式插入到 html 中
    • 命令行:npx webpack
    • 会生成对应的.html.css.js文件
    • 可以打开.html文件看看内容,同时也可以运行一下.html看看样式是否生效,js文件是否正常加载。
    image.png

css预处理器

css发展这么多年,性能,功能什么的已经突飞猛进,但是对于循环、分支判断、扩展复用、函数、嵌套之类的特性还是缺失的,以至于原生 CSS 已经难以应对当代复杂 Web 应用的开发需求。
于是社区就产出了功能更强大的 CSS 预处理器,,比较知名的有 LessSassStylus
这些工具各有侧重,但都在 CSS 之上补充了扩展了一些逻辑判断、数学运算、嵌套封装等特性,基于这些特性,我们能写出复用性、可读性、可维护性更强,条理与结构更清晰的样式代码。
本节主要讲Less

  • 安装依赖
    • 命令行: npm i -D less less-loader
    • 配置webpack.config.js
    const path = require('path');
    const EslintPlugin = require('eslint-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const HTMLWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        mode: 'development',
        entry: {
            index: './src/index.js',
            test: './src/test.ts'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
            // 省掉了之前的配置,less只需要下面的配置就可以了
                {
                    test: /.less$/,
                    use: [
                        'style-loader',
                        'css-loader',
                        'less-loader'
                    ]
                }
            ]
        },
        resolve: {
            extensions: ['.ts', '.js'],
        },
        plugins: [
            new EslintPlugin({
                extensions: ['.ts', '.js']
            }),
            new MiniCssExtractPlugin(),
            new HTMLWebpackPlugin()
        ]
    }
    
    • 创建.less文件
    // 变量
    @size: 12px;
    @color: #006633;
    
    // 混合
    .mx-bordered() {
      border: 1px solid #000;
    }
    
    // 嵌套
    body {
      // 函数计算
      background: spin(lighten(@color, 25%), 8);
      font-weight: bold;
      padding: @size;
    
      .main {
        // 数学运算
        font-size: @size * 2;
        .mx-bordered;
        color: darken(@color, 10%);
        padding: @size * 0.6;
      }
    }
    
    • index.js引入.less文件
    import './index.css'
    import './index.less'
    
    const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    list.map(item => item)
    
    • 编译,命令行输入:npx webpack
    • 运行生成后的index.html文件查看效果

除了less,其他的两种接入的方式也很简单
Sassnpm i -D sass-loader
Stylus: npm i -D stylus-loader
webpack.config.js配置也很一样,就是把less换成对应的名字就好了。

使用 post-css

post-css是什么?
post-css就会说css版的babel,不同的是babel会改造或者创建js语法为兼容低版本的js语法,post-css就是增加兼容性前缀。

  • 使用post-css

    • 安装依赖
    • 命令行:npm i -D postcss postcss-loader autoprefixer
    • 配置webpack.config.js
    const path = require('path');
    const EslintPlugin = require('eslint-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const HTMLWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        mode: 'development',
        entry: {
            index: './src/index.js',
            test: './src/test.ts'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /.css$/,
                    use: [
                        (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader),
                        {
                            loader: "css-loader",
                            options: {
                                importLoaders: 1 // 主要是用来处理@import引入的css,如果不加这个,@import引入的css不会被postcss-loader处理
                            }
                        },
                        {
                            loader: "postcss-loader",
                            options: {
                                postcssOptions: {
                                    // 添加 autoprefixer 插件
                                    plugins: [require("autoprefixer")],
                                },
                            },
                        }
                    ]
                },
            ]
        },
        resolve: {
            extensions: ['.ts', '.js'],
        },
        plugins: [
            new EslintPlugin({
                extensions: ['.ts', '.js']
            }),
            new MiniCssExtractPlugin(),
            new HTMLWebpackPlugin()
        ]
    }
    
    • 完了之后在.css文件中写点新颖的css,例如伪类::placeholder
    • 然后npx webpack
    • 然后就可以查看生成的.css文件的内容了

    image.png

  • post-css的配置可以单独抽离出来处理

    • 创建postcss.config.js,内容如下:
    module.exports = {
        plugins: [
            require("autoprefixer")
        ],
    };
    
    • 然后webpack.config.js就可以下面这样了
    // 省略其他的配置
    module.exports = {
        module: {
            rules: [
                {
                    test: /.css$/,
                    use: [
                        (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader),
                        {
                            loader: "css-loader",
                            options: {
                                importLoaders: 1
                            }
                        },
                        'postcss-loader', // 可以不加配置属性,简写了
                    ]
                },
                {
                    test: /.less$/,
                    use: [
                        'style-loader',
                        {
                            loader: "css-loader",
                            options: {
                                importLoaders: 1
                            }
                        },
                       'postcss-loader', // 和预处理器是兼容的,但是需要预处理器处理完了之后再给它处理哟,不要弄错顺序了
                        'less-loader',
                    ]
                }
            ]
        },
    }
    

总结

总结都是课程里面的,自己的总结就是配置好了,可以使用了,后面默认都知道我的总结了

本文介绍 css-loaderstyle-loadermini-css-extract-pluginless-loaderpostcss-loader 等组件的功能特点与接入方法,内容有点多,重点在于:

  • Webpack 不能理解 CSS 代码,所以需要使用 css-loaderstyle-loadermini-css-extract-plugin 三种组件处理样式资源;
  • Less/Sass/Stylus/PostCSS 等工具可弥补原生 CSS 语言层面的诸多功能缺失,例如数值运算、嵌套、代码复用等。

这些工具几乎已经成为现代 Web 应用开发的标配,能够帮助我们写出更清晰简洁、可复用的样式代码,帮助我们解决诸多与样式有关的工程化问题。