# SASS
提示
本节为可选内容,Less (opens new window)、Stylus (opens new window) 的使用与本节 Sass (opens new window) 类似。
由于 CSS 缺少可编程性,写出来的代码会有大量重复。一般项目中会使用 CSS 预处理工具,Sass
、Less
、Stylus
。这里将使用 Sass
作为参考,其他工具类似。
# 改造
为了后续内容的展开,我们需要创建 src/style/element.scss
文件对 src/style/element.css
内容进行改造迁移。并且将 src/element.ts
对 .css
的引用改为该文件。
// src/style/element.scss
.ui {
&-random-text {
display: inline-block;
font-size: 16px;
font-weight: bold;
color: coral; // 顺便改个颜色
writing-mode: vertical-lr;
}
&-backgroud-body {
border-radius: 50%;
box-shadow: grey 10px 10px 10px 0;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/element.ts
import "./style/element.scss";
// import "./style/element.css";
import * as util from "./util";
// 使用 background 显示图片
export async function createBackgroudImg(src: string) {
// ...
}
// 创建一个有随机数的节点
export function createRandomTextElement() {
// ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
运行 node build.js
,结果就是编译失败。原因和之前的章节类似,目前无法为识别 .scss
文件,需要做一些处理。
# 整体编译
处理 .scss
文件就需要用到 sass (opens new window) 包。如果是要想 Webpack 能处理 scss
文件,那么还需要给 Webpack 加一个 loader。将 .scss
文件编译成 .css
再交给 css-loader
做处理,这个 loader 就是 sass-loader (opens new window)。
# 安装
npm install sass --save-dev
# 如果是在 Webpack 使用还需要安装以下
npm install sass-loader --save-dev
2
3
4
// ...
webpack(
{
// ...
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
require("autoprefixer")({
overrideBrowserslist: ["ie >= 11"],
}),
],
},
},
},
"sass-loader",
],
},
// ...
],
},
plugins: [new MiniCssExtractPlugin()],
}
// ...
);
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
运行 node build.js
,重新在浏览器打开 index.html
,均正常运行,并且颜色也调整了。
# 单独编译
和前面几章一样。还要对按需加载方式的文件进行处理,根据 Nodejs API 官方文档 (opens new window) 对 compile.js
进行调整:
// compile.js
// 相当于 run-babel.js 的升级版
var stream = require("stream");
var { src, dest } = require("gulp");
var babel = require("@babel/core");
var postcss = require("postcss");
var sass = require("sass");
function compileTS(modules) {
// ...
}
function compileCSS(modules) {
// Commonjs 输出至 ./lib
// ES6 Module 输出至 ./es
var path = modules === false ? "./es" : "./lib";
// 读取 scss 文件,而不是 css 了
src("./src/**/*.scss")
.pipe(
// 将 scss 转化成 css
new stream.Transform({
objectMode: true,
transform: function(chunk, encoding, next) {
var result = sass.renderSync({ file: chunk.path });
chunk.contents = Buffer.from(result.css);
// 后缀名文件 .scss -> .css
chunk.extname = ".css";
next(null, chunk);
},
})
)
.pipe(
// 上面处理好的 css 再进行兼容性处理
new stream.Transform({
objectMode: true,
transform: function(chunk, encoding, next) {
// 传入配置
postcss([
require("autoprefixer")({
// 可以对比添加前后的产物有什么区别
// 注意这里是不兼容 IE <= 11,为了查看添加前后的区别
// overrideBrowserslist: ["> 1%", "not ie <= 11"],
overrideBrowserslist: ["ie >= 11"],
}),
])
.process(chunk.contents.toString(encoding), { from: chunk.path })
.then((result) => {
chunk.contents = Buffer.from(result.css);
next(null, chunk);
});
},
})
)
.pipe(dest(path)); // 输出到某文件中
}
// 编译 TS
compileTS(false);
compileTS();
// 编译 CSS
compileCSS(false);
compileCSS();
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
62
63
64
运行 node complie.js
,编译完后打开 http://localhost:3000/
会发现浏览器控制台会发出 Uncaught Error: Cannot find module './style/element.scss'
错误。意思就是没有 lib/style/element.scss
或 es/style/element.scss
文件,可我们期望引入的是编译好的 lib/style/element.css
或 es/style/element.css
,并且这两个文件当前是存在的。
之所以会出现上述情况,是因为我们将 .ts
⇨ .js
,.scss
⇨ .css
。但是 .ts
里面的文件路径是不会进行调整的。例如:原本 .ts
文件引入的是 xx/xx.scss
,那么转化成 .js
的内容还是 xx/xx.scss
。可以打开编译产物 lib/element.js
或 es/element.js
进行查看:
// lib/element.js
"use strict";
var _typeof = require("@babel/runtime-corejs3/helpers/typeof");
var _WeakMap = require("@babel/runtime-corejs3/core-js-stable/weak-map");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true,
});
exports.createBackgroudImg = createBackgroudImg;
exports.createRandomTextElement = createRandomTextElement;
var _regenerator = _interopRequireDefault(
require("@babel/runtime-corejs3/regenerator")
);
var _asyncToGenerator2 = _interopRequireDefault(
require("@babel/runtime-corejs3/helpers/asyncToGenerator")
);
require("./style/element.scss");
var util = _interopRequireWildcard(require("./util"));
// 以下文件内容省略
// ...
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
// es/element.js
import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator";
import "./style/element.scss";
import * as util from "./util"; // 使用 background 显示图片
2
3
4
5
6
7
我们需要将原本引入的 .scss
改为 .css
,例如:require("./style/element.scss");
字符串调整为 require("./style/element.css");
。可以在 .ts
⇨ .js
的过程使用正则表达式对 style/xxx.scss
字符串进行全局匹配替换。调整 compile.js
实现前面描述的逻辑:
var stream = require("stream");
var { src, dest } = require("gulp");
var babel = require("@babel/core");
var postcss = require("postcss");
var sass = require("sass");
function compileTS(modules) {
// babel 配置
var config = {
presets: [
["@babel/preset-env", { modules, debug: true, targets: "IE >= 11" }],
"@babel/preset-typescript",
],
plugins: [["@babel/plugin-transform-runtime", { corejs: 3 }]],
};
// Commonjs 输出至 ./lib
// ES6 Module 输出至 ./es
var path = modules === false ? "./es" : "./lib";
// 读取文件
src("./src/**/*.ts")
.pipe(
// 可以使用 through2 库,会更方便
// 创建转化流,类似于双工流,但其输出是其输入的转换的转换流。
new stream.Transform({
objectMode: true,
transform: function(chunk, encoding, next) {
// 转化逻辑
babel.transform(
chunk.contents.toString(encoding), // 文件内容
// 需要额外添加 filename
{ ...config, filename: chunk.basename },
(err, res) => {
// 文件中的 style/xxx.scss -> style/xxx.css
const content = res.code.replace(
/([\\/]style[\\/](?:.+)).scss/g,
"$1.css"
);
// 文件内容修改成转化后的代码
chunk.contents = Buffer.from(content);
// 后缀名文件 .ts -> .js
chunk.extname = ".js";
next(null, chunk);
}
);
},
})
)
.pipe(dest(path)); // 输出到某文件中
}
function compileCSS(modules) {
// ...
}
// 编译 TS
compileTS(false);
compileTS();
// 编译 CSS
compileCSS(false);
compileCSS();
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
62
63
重新运行 node compile.js
,编译完后在浏览器打开 http://localhost:3000/
,结果正常运行。也可以查看编译产物 lib/style/element.js
或 es/style/element.js
文件是否对引入的 .scss
路径进行替换。