# CSS

提示

本节为可选内容,如果是开发前端组件库,那你可能需要本节内容。

# 准备

对现有的代码稍作修改,以此为基础展开本节内容。创建 src/style/element.css 写些样式类,src/util.ts 使用其样式。

/* src/style/element.css */
.ui-random-text {
  display: inline-block;
  font-size: 16px;
  font-weight: bold;
  color: cornflowerblue;
  writing-mode: vertical-lr;
}

.ui-backgroud-body {
  border-radius: 50%;
  box-shadow: grey 10px 10px 10px 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

 










 







 






// src/element.ts
import "./style/element.css";
import * as util from "./util";

// 使用 background 显示图片
export async function createBackgroudImg(src: string) {
  const img = await util.loadImg(src);

  const div = document.createElement("div");
  div.style.width = `${img.width}px`;
  div.style.height = `${img.height}px`;
  div.style.background = `url(${src})`;
  div.classList.add("ui-backgroud-body");

  return div;
}

// 创建一个有随机数的节点
export function createRandomTextElement() {
  const div = document.createElement("div");
  div.classList.add("ui-random-text");
  div.innerText = `random: ${util.getRandomInt(1000, 9999)}`;
  return div;
}

// 类、await、async 的演示代码删除,有兴趣也可以自己转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 构建

此时重新打包是无法工作的,因为 Webpack 只能解析 .js 文件,遇到 .css 文件时将无法正常工作。所以我们需要使用 css-loader.css 解析成 .js 交给 style-loader。而 style-loader 通过 <style> 插入到 <head> 中,实现样式应用。

# 安装
npm install style-loader css-loader --save-dev
1
2

























 
 
 
 
 
































// build.js
var path = require("path");
var webpack = require("webpack");

webpack(
  {
    // 需要设置 production,自动开启代码优化功能
    // 或设置以下 optimization 手动开启代码优化功能
    mode: "none", // 方便查看产物的代码,可以临时设置 none
    // 入口
    entry: "./src/index.ts",
    // 输出
    output: {
      filename: "library.js",
      path: path.resolve(__dirname, "dist"),
      library: {
        name: "library",
        type: "umd",
      },
    },
    target: ["web", "es5"],
    // 顺序解析后缀名
    resolve: { extensions: [".ts", ".js", ".json"] },
    module: {
      rules: [
        {
          test: /\.css$/,
          // 顺序不能错,loader 从右往左执行
          use: ["style-loader", "css-loader"],
        },
        {
          test: /\.(ts)|(m?js)$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            // 传入配置方式 或者 创建配置文件
            options: {
              presets: [
                ["@babel/preset-env", { debug: true, targets: "ie >= 11" }],
                "@babel/preset-typescript",
              ],
              plugins: [["@babel/plugin-transform-runtime", { corejs: 3 }]],
            },
          },
        },
      ],
    },
    // optimization: {
    //   usedExports: true,
    //   minimize: true,
    //   concatenateModules: true,
    // },
  },
  (err, stats) => {
    if (err || stats.hasErrors()) {
      // 这里处理错误
      console.log(err, stats);
    }
    // 处理完成
  }
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

运行 node build.js,打开 index.html。只有 writing-mode 在 IE 显示无效,样式在 Chrome 显示正常,Postcss 小节中将会解决该问题。除此之外,还可以发现产物依旧只有一个(dist/library.js) 。在绝大多数 UI 组件库中, cssjs 均是分开引入的,这个问题将在 下节 解决。

Chrome 运行效果图 IE 运行效果图

# 提取

上节说到产物只有一个 dist/library.js 文件,里面包含了 css。而我们需要单独提取出来,这样用户才能将 cssjs 分开引入。这里就需要用到 Webpack 的 MiniCssExtractPlugin (opens new window) 插件了,它可以将 CSS 提取成单独的文件。

注意

如果用到 MiniCssExtractPlugin 就不需要使用 style-loader,因为这两个插件的功能是互斥的。一个是将 CSS 文件提取成单独的文件然后需要手动引入,一个是自动将 CSS 挂载到 <head></head> 中。

# 安装
npm install mini-css-extract-plugin --save-dev
1
2
// build.js
// ...
var MiniCssExtractPlugin = require("mini-css-extract-plugin");

webpack(
  {
    // ...
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [MiniCssExtractPlugin.loader, "css-loader"],
        },
        // ...
      ],
    },
    plugins: [new MiniCssExtractPlugin()],
  }
  // ...
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

运行 node build.js,运行成功后会多出 dist/main.css。这时也需要对 index.html 文件改造:手动将 .css 文件引入上。









 
























<!-- 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>Document</title>
    <link rel="stylesheet" href="./dist/main.css" />
  </head>
  <body>
    <!-- <script src="./library.js"></script> -->
    <script src="./dist/library.js"></script>
    <script>
      // 随机数文本节点
      var randomText = window.library.createRandomTextElement();
      document.body.appendChild(randomText);

      // 显示浏览器类型
      var browserText = document.createElement("div");
      browserText.innerHTML = window.library.browser();
      document.body.appendChild(browserText);

      // 添加图片 callback -> Promise
      window.library
        .createBackgroudImg("https://hxin.link/images/avatar.jpg")
        .then(function(el) {
          document.body.appendChild(el);
        });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

重新打开 index.html,就可以发现样式应用上了。

提示

如果这里运行 node compile.jsnode example/serve.js 打开 http://localhost:3000/。浏览器会抛出错误 Uncaught Error: Cannot find module './style/element.css' 异常。这个是因为 compile.js 没有对 .css 文件进行处理,libes 文件夹下并没有对应的 .css 文件。这个问题会在 Postcss 单独编译 小节一同解决,如果不想使用 Postcss,可以在 compile.js 增加对 .css 逻辑的处理。例如:将 .css 文件从 src 拷贝至对应的输出文件夹。