跳至主要內容

webpack 打包 CSS

njr工程化项目打包webpack大约 5 分钟约 1568 字

项目地址:https://github.com/Stephen-wzw/webpack-demoopen in new window

继续使用之前的项目,不过在以下文件做点修改:

index.html

 <!DOCTYPE html>
 <html lang="en">
 <head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>webpack-demo</title>
+  <title>webpack-css</title>
 </head>
 <body>
-  <script src="./dist/main.js" type="module"></script>
+  <script src="./dist/bundle.js" type="module"></script>
 </body>
 </html>

webpack.config.js

 const path = require("path");
 
 module.exports = {
   entry: "./src/index.js",
   output: {
-    filename: "main.js",
+    filename: "bundle.js",
     path: path.resolve(__dirname, "dist"),  // 需要使用绝对路径
   },
 };

bundle.js 表示为打包的文件,见名知意。

修改完配置文件后,下面在项目中添加一个 style.css 文件,并将其 importindex.js 中:

project

  webpack-demo
  |- node_modules
  |- package-lock.json
  |- package.json
  |- index.html
  |- /src
+   |- /css
+     |- style.css
    |- /js
      |- format.js
      |- math.js  
    |- index.js

style.css

.title {
  color: #000;
  font-weight: 700;
  font-size: 30px;

  user-select: none;
}

index.js

 import { sum } from "./js/math.js";
 const { priceFormat } = require("./js/format");
+import "../css/style.css";
 
 console.log(sum(10, 20));
 console.log(priceFormat());
 
+const div = document.createElement("div");
+div.className = "title";
+div.innerHTML = "webpack-css";
+document.body.appendChild(div);

css-loader

现在执行 npm run build,会看到报错:

ERROR in ./src/css/style.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .title {
|   color: #000;
|   font-weight: 700;
 @ ./src/index.js 3:0-25

从报错信息中可以知道,需要用一个 loader 处理 css 文件。那么什么是 loader 呢?

  • loader 用于对模块的源代码进行转换;
  • loader 可以使你在 import 或 "load(加载)" 模块时预处理文件;
  • loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!

而为了能在项目中正常使用 css,需要用到 css-loader

npm install css-loader -D

接下来需要在 webpack.config.js 中配置 css-loader 的使用:

 const path = require('path');

 module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
+ module: {
+   rules: [
+     {
+       test: /\.css$/i,
+       use: ['css-loader'],
+     },
+   ],
+ },
 };

此时再次执行 npm run build,虽然不报错了,但是样式并没有应用成功,这是为什么呢?难道是 css-loader 不起作用吗?

这是因为 css-loader 只能将 .css 文件导入到 JavaScript 文件中,也就是它只负责解析,不负责将解析后的 css 插入到页面中

如果希望完成这个插入操作,需要用到 style-loader

style-loader

npm install style-loader -D

同时在 webpack.config.js 中配置 style-loader 的使用:

 const path = require("path");
 
 module.exports = {
   entry: "./src/index.js",
   output: {
     filename: "bundle.js",
     path: path.resolve(__dirname, "dist"),  // 需要使用绝对路径
   },
   module: {
     rules: [
       {
         test: /\.css$/i,
-        use: ['css-loader'],
+        use: ['style-loader', 'css-loader'],
       },
     ],
   },
 };

style-loader 需要写在 css-loader 之前,因为 loader 的执行顺序是从后往前的。

现在重新执行 npm run build,可以发现样式已经生效了。

less-loader

在实际开发中,我们可能会使用 less、sass 等预处理器来编写 css 样式,那么如何让项目中支持这些预处理器呢?比如说支持 less。

现在在项目中新增 title.less 文件:

project

  webpack-demo
  |- node_modules
  |- package-lock.json
  |- package.json
  |- index.html
  |- /src
    |- /css
      |- style.css
+     |- title.less
    |- /js
      |- format.js
      |- math.js  
    |- index.js

title.less

@bgColor: blue;
@textDecoration: underline;

.title {
  background-color: @bgColor;
  text-decoration: @textDecoration;
}

index.js

 import { sum } from "./js/math.js";
 const { priceFormat } = require("./js/format");
 import "./css/style.css";
+import "./css/title.less";
 
 console.log(sum(10, 20));
 console.log(priceFormat());
 
 const div = document.createElement("div");
 div.className = "title";
 div.innerHTML = "webpack-css";
 
 document.body.appendChild(div);

现在我们需要安装 less-loader 来处理 .less 文件:

npm install less-loader -D

less-loader 会自动使用 less 工具将 .less 文件转换为 .css 文件。

同时在 webpack.config.js 中配置 less-loader 的使用:

 const path = require("path");
 
 module.exports = {
   entry: "./src/index.js",
   output: {
     filename: "bundle.js",
     path: path.resolve(__dirname, "dist"),  // 需要使用绝对路径
   },
   module: {
     rules: [
       {
-        test: /\.css$/i,
+        test: /\.(less|css)$/,
-        use: ['style-loader', 'css-loader'],
+        use: ['style-loader', 'css-loader', 'less-loader'],
       },
     ],
   },
 };

现在重新执行 npm run build,可以发现 less 样式已经生效了。

post-css-loader

开发中除了使用预处理器外,还可能需要使用 CSS 后处理器 postcss。他能帮我们进行 CSS 的转换和适配,比如自动添加浏览器前缀、CSS 样式的重置。

首先安装 postcsspostcss-loader

npm install postcss postcss-loader -D

还需要安装自动添加前缀的插件 autoprefixer

npm install autoprefixer -D

此时配置 webpack.config.js

webpack.config.js

  const path = require("path");
  
  module.exports = {
    entry: "./src/index.js",
    output: {
      filename: "bundle.js",
      path: path.resolve(__dirname, "dist"),  // 需要使用绝对路径
    },
    module: {
      rules: [
        {
          test: /\.(less|css)$/,
          use: [
            'style-loader', 
            'css-loader', 
+           {
+             loader: 'postcss-loader',
+             options: {
+               postcssOptions: {
+                 plugins: [
+                   require("autoprefixer")
+                 ]
+               }
+             }
+           },
           'less-loader'],
        },
      ],
    },
  };

执行 npm run build 打包,在浏览器中查看样式,即可看到 postcss 为我们自动添加了前缀:

.title {
  color: #000;
  font-weight: 700;
  font-size: 30px;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

postcss.config.js

以上的这些配置信息太长了,我们可以将它们单独在一个文件中进行配置,在项目根目录下新建 postcss.config.js

postcss.config.js

module.exports = {
  plugins: [
    require("autoprefixer")
  ]
};

webpack.config.js

const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"), // 需要使用绝对路径
  },
  module: {
    rules: [
      {
        test: /\.(less|css)$/,
+       use: ["style-loader", "css-loader", "postcss-loader", "less-loader"],
      },
    ],
  },
};

重新打包后打开浏览器样式依然生效。

postcss-preset-env

事实上,在配置 postcss-loader 的时候,配置插件并不需要使用 autoprefixer。可以使用另一个插件 postscc-preset-env,它可以帮助我们将一些现代的 CSS 特性,转成大多数浏览器认识的 CSS,并且会根据目标浏览器或者运行时环境添加所需的 ployfill。

ployfill 用来为旧浏览器提供它没有原生支持的较新的功能。比如说 polyfill 可以让 IE7 使用 Silverlight 插件来模拟 HTML Canvas 元素的功能,或模拟 CSS 实现 rem 单位的支持,或 text-shadow,或其他任何你想要的功能。

这个插件也会自动帮我们添加 autoprefixer。

npm install postcss-preset-env -D

然后修改下 postcss.config.js 文件。

postcss.config.js

 module.exports = {
   plugins: [
-    require("autoprefixer")
+    // 在使用某些插件时,也可以直接传入字符串
+    "postcss-preset-env"
   ]
 };

重新打包后打开浏览器样式依然生效。

postcss-px-to-viewport

这个插件可以帮助我们将 px 单位转换为视口单位,这在进行移动端适配时尤为重要。详细使用见 postcss-px-to-view

总结

在这个案例里,我们分别使用了 style-loader 加载 css 样式, css-loader 处理 .css 文件, less-loader 处理 .less 文件,以及使用 postcss 给样式自动添加前缀。

loader 的执行顺序是从后往前的,因此需要配置规则中写成 use: ["style-loader", "css-loader", "postcss-loader", "less-loader"]