前端工程化项目搭建三:css加载

83 阅读3分钟

这是我参与「掘金日新计划 · 8 月更文挑战」的第2天

前言

前面完成了webpack5配置中的基本配置,包括html的渲染,运行和打包命令,开发环境的基本配置,接下来就是css加载的配置了。

css加载

webpack运行环境是在node,而node环境下打包只能处理js文件间的依赖,对于.css这类后缀的文件,由于不是一个js模块,那就需要特殊的工具进行处理,也就是loader。
而传统引入css文件的方式,都是通过在 html 写上对应的标签进行加载资源,如:<style>

css加载方式介绍

style标签方式

使用这种方式需要使用到css-loader和style-loader,那么就下载一下依赖吧

npm i -D css-loader style-loader
  • css-loader的作用,是用来识别并加载css
  • style-loader的作用,是用来将css转化为html的style节点。
    下载好依赖之后,在webpack.config.js文件中增加module属性,配置如下:
module.exports = {
    ...
    module: {
    rules: [
      {
        test: /\.css$/,
        // use: ["style-loader", "css-loader"]
        use: [
          { loader: "style-loader" },
          {
            loader: "css-loader",
            options: {
              modules: true // 启用/禁用 CSS 模块及其配置
            }
          }
        ]
      }
    ]
  }
}

顺便提醒一下,loader的加载顺序是从右到左(从下到上)
在src下创建css文件夹,并创建一个css文件---index.css,内容如下

// src/css/index.css
body {
    background: pink;
}

执行编译之后,页面控制台内容如下图:

image.png

页面展示如下图:

image.png

那么,再执行一下打包命令看看:

image.png

发现,在html中,并没有出现style标签,然后,在打包好的js文件中,发现了这么一句:

...
s.push([e.id,"body {\r\n  background-color: pink;\r\n}\r\n",""]),

不难发现,这就是我们在css文件中写下的样式代码,这就说明,<style>标签实际上是js动态插入的。

独立css文件方式

除了传统的style标签引入,我们还可以使用独立css文件的方式,这样的好处就是,css的文件是独立,做到了样式文件分离的目的。使用这种方式,则不需要下载style-loader依赖,需要用到的插件则是mini-css-extract-plugin,这个插件的作用,便是提取css到单独的文件中了。
webpack.config.js文件配置修改如下:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  plugins: [
    ...
    new MiniCssExtractPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      }
    ]
  }
};

运行打包命令后,会生成一个css文件在指定的打包文件夹下。

image.png

image.png

然,此时的css文件是没有压缩的,那么,在打包时候,也要对css文件进行压缩打包,不过,开发环境不需要,所以压缩css的配置,便不用在公共config配置中。

css压缩

插件:css-minimizer-webpack-plugin。

// webpack.config.prod.js
module.exports = merge(config, {
  mode: "production",
  ...
  optimization: {
    minimizer: [new CssMinimizerPlugin()]
  }, // 优化
  devServer: {
    compress: true
  }
});

再次运行打包命令,会发现,css文件被压缩了。然后,此时又会发现,js文件没有被压缩了,因为,我们覆盖了默认压缩行为。查看官方文档会发现这么一句话:optimization.minimizer中可以使用'...' 来访问默认值,那么,我们也加上,再次运行打包命令,此时,js文件和css文件均压缩了。

// webpack.config.prod.js
module.exports = merge(config, {
  mode: "production",
  ...
  optimization: {
    minimizer: [new CssMinimizerPlugin(), "..."]
  }, // 优化
  devServer: {
    compress: true
  }
});

在日常开发中,在写css的时候,相信大部分人都是使用sass或者less,而webpack自身也是无法解析这两类文件的,此时,我们需要新的方法来解决这个问题(以sass为例)。

加载scss,sass

安装 sass sass-loader
修改webpack.config.js配置

module.exports = {
  plugins: [
    ...
    new MiniCssExtractPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      },
      {
        test: /\.s[ac]ss$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      }
    ]
  }
};

运行打包命令后,会发现,在css文件中,出现了新的css样式

image.png

后续如果使用像less之类的,配置方式差不多是一样的啦。

指定打包文件夹

至此,基本的配置就完成了。但是,css并没有像js那样有独立的文件夹,这个可以配置吗?答案当然是可以的啦。

// webpack.config.js
new MiniCssExtractPlugin({
    filename: "css/[name].[fullhash].css"
})

// webpack.config.prod.js
 output: {
    filename: "js/[name].[hash].js",
    path: path.resolve(__dirname, "../dist_prod"), // 指定打包文件夹
    clean: true // 磁盘空间会存有打包后的资源,在再次打包的时候,我们需要先把本地已有的打包后的资源清空,来减少它们对磁盘空间的占用
},

像这样,在filename前加上文件夹名,可以实现文件分类到不同的文件夹。

展示完整代码

目录

image.png

main.js文件

import "./index.js";
import "./css/index.css";
import "./scss/index.scss";
console.log(process.env.NODE_ENV);

webpack.config.js

// webpack.config.js
const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  entry: path.resolve(__dirname, "../src/main.js"), // path.resolve 方法用于生成绝对路径
  plugins: [
    new webpack.LoaderOptionsPlugin({
      // test: /\.xxx$/, // may apply this only for some modules
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"), // 指定要编译的文件,不指定的话会按照默认的模板创建一个html
      title: "webpack练习",
      filename: "index.html" // 编译完成输出的文件名
    }),
    new MiniCssExtractPlugin({
      filename: "css/[name].[fullhash].css"
    })
  ],
  module: {
    rules: [
      // {
      //   test: /\.css$/,
      //   // use: ["style-loader", "css-loader"]
      //   use: [
      //     { loader: "style-loader" },
      //     {
      //       loader: "css-loader",
      //       options: {
      //         modules: true // 启用/禁用 CSS 模块及其配置
      //       }
      //     }
      //   ]
      // }
      // loader,源码预处理器
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      },
      {
        test: /\.s[ac]ss$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      }
    ]
  }
};

webpack.config.prod.js

const { merge } = require("webpack-merge");
const config = require("./webpack.config");
const path = require("path");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = merge(config, {
  mode: "production",
  output: {
    filename: "js/[name].[hash].js",
    path: path.resolve(__dirname, "../dist_prod"), // 指定打包文件夹
    clean: true // 磁盘空间会存有打包后的资源,在再次打包的时候,我们需要先把本地已有的打包后的资源清空,来减少它们对磁盘空间的占用
  },
  optimization: {
    minimizer: [new CssMinimizerPlugin(), "..."]
  }, // 优化
  devServer: {
    compress: true
  }
});

webpack.config.dev.js

const { merge } = require("webpack-merge");
const config = require("./webpack.config");
const path = require("path");
module.exports = merge(config, {
  mode: "development",
  devServer: {
    port: 8080, // 端口号
    hot: true //文件修改自动刷新
  }
});

参考资料

webpack5的使用
webpack官网