Lan Tian @ Blog

与 Hexo 配合使用 Sass 和 Webpack

为何使用 Sass 和 Webpack

Sass 是 CSS 的超集,在 CSS 的基础上扩展了大量的语法,支持规则嵌套、变量定义、include 等功能,也可以进行数学运算。主要功能可以在官方入门教程中查看。Sass 原先的文件格式扩展名是 sass,其结构类似 yaml,似乎不与传统 CSS 兼容;而目前 Sass 的文件格式是 scss,兼容 CSS 文件。

我使用 Sass 的目的,一是更加清晰的 CSS 规则管理。例如,我有一些 CSS 规则希望只对网站顶栏生效,我就可以将它们全部放到一个代码块中方便管理:

1
2
3
header {
h1 { ... }
}

二是减少网页加载时的 CSS 代码量。虽然我的网站使用了 Bootstrap,但是我只使用了一小部分功能,即 Bootstrap 的栅格系统,导航栏和下拉菜单,其它大部分功能都没有使用,这部分 CSS 就不必加载。同时,我还通过 CSS !important 覆盖的方式对一些 Bootstrap 的颜色、形状进行了自定义,这也引入了额外的代码量。

我在我的 scss 文件中定义了全局的控件颜色、字体大小等,同时自己 include Bootstrap 的 scss 文件,注释掉我不需要的功能,最后产生的 CSS 文件大小也会大幅下降。

另外 Sass 产生的 CSS 是合并成一个缩减过大小(Minify)的,最后将这一个文件传上服务器就好。

我使用 Webpack 也是类似的原因:去除我不需要的 Bootstrap JS 功能,并将 JS 代码压缩并合并成一个文件。

还有一点:Sass 和 Webpack 可以与 npm 共同使用,用 npm 更新 Bootstrap 等框架的最新代码,并在 Sass 和 Webpack 的 JS 文件中共同使用。

在 Hexo 中使用 Sass 和 Webpack

Hexo 作为一款流行的静态网站生成工具,有大量的插件。我使用的插件是 hexo-renderer-sasshexo-webpack

1
2
npm install --save hexo-renderer-sass
npm install --save hexo-webpack

对于 Sass,由于我要 include npm 安装的框架代码,需要在主题的 _config.yml 中加入如下代码,让 Sass 去 node_modules 文件夹下找 npm 安装的模块:

1
2
3
4
node_sass:
includePaths:
- "node_modules"
outputStyle: compressed

以 Bootstrap 为例,先用 npm 安装:

1
npm install --save bootstrap

再在自己的 styles.scss 文件中 include:

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
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
// @import "bootstrap/scss/images";
// @import "bootstrap/scss/code";
@import "bootstrap/scss/grid";
// @import "bootstrap/scss/tables";
// @import "bootstrap/scss/forms";
// @import "bootstrap/scss/buttons";
// @import "bootstrap/scss/transitions";
@import "bootstrap/scss/dropdown";
// @import "bootstrap/scss/button-group";
// @import "bootstrap/scss/input-group";
// @import "bootstrap/scss/custom-forms";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
// @import "bootstrap/scss/card";
// @import "bootstrap/scss/breadcrumb";
// @import "bootstrap/scss/pagination";
// @import "bootstrap/scss/badge";
// @import "bootstrap/scss/jumbotron";
// @import "bootstrap/scss/alert";
// @import "bootstrap/scss/progress";
// @import "bootstrap/scss/media";
// @import "bootstrap/scss/list-group";
// @import "bootstrap/scss/close";
// @import "bootstrap/scss/toasts";
// @import "bootstrap/scss/modal";
// @import "bootstrap/scss/tooltip";
// @import "bootstrap/scss/popover";
// @import "bootstrap/scss/carousel";
// @import "bootstrap/scss/spinners";
@import "bootstrap/scss/utilities";
// @import "bootstrap/scss/print";

对于 Webpack,由于我使用的一些 JS 模块依赖 jQuery,但它们是原生 JS 模块,缺少相应在 Webpack 中加载 jQuery 模块的指令,因此需要修改 Webpack 配置在主题目录(与 _config.yml 同一文件夹)下创建 webpack.config.js 文件,使用 Webpack 的 ProvidePlugin 为它们直接提供 jQuery 环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const webpack = require('webpack');

module.exports = {
entry: 'assets/script.js',
output: {
filename: 'script.bundle.js',
path: 'assets',
},
mode: 'production',
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
]
};

上述配置的入口 JS 文件在 assets/script.js,最后生成文件在 assets/script.bundle.js

再以 Bootstrap 为例,在 script.js 中用这一行代码,就可以导入 Bootstrap 的下拉菜单模块,以及它依赖的 jQuery 和 Popper.js:

1
import 'bootstrap/js/src/dropdown';

其它模块同理。

最后修改主题的 head 区域加载最后生成的 CSS 和 JS 文件:

1
2
<link rel="stylesheet" href="<%- url_for('assets/style.css') %>" />
<script src="<%- url_for('assets/script.bundle.js') %>"></script>

hexo generate 即可。