Bootstrap 是一个流行的前端样式库,可以方便快速的构建应用,但默认样式可能不尽人意,本文就介绍如何使用 NPM, Webpack, SASS
针对它的源码来定制自己的主题。版本使用的是 Bootstrap v4.3.1。

本文提供了一个使用此方式编写的一个后台管理模板 Dunwoo Admin,文末有获取源码的方式。



安装 Node.js

Webpack 是对前端资源进行打包和编译的工具,它依赖于 Node.js,首先介绍下如何配置和安装绿色版的 Node.js。

下载绿色版本:https://nodejs.org/en/download/ (以 node-v10.16.1-win-x64.zip 为例)

并解压到某个目录下,比如 D:\node-v10.16.1, 然后设置系统环境变量:
NODE_HOME=D:\node-v10.16.1 NODE_PATH=%NODE_HOME%\node_modules
path=增加;%NODE_HOME%;
在 Node.js 主目录新建 node_global 和 node_cache 两个目录,并使用以下命令设置 npm 全局安装模块的位置以及下载缓存路径:
npm config set prefix "D:\node-v10.16.1\node_global" npm config set cache
"D:\node-v10.16.1\node_cache"
最后,可以在命令行使用 node -v 和 npm -v 验证是否安装成功。

Webpack 安装和配置

安装 Webpack 之前,需要使用 npm init 在项目根目录生成一个 package.json 文件,它类似 Java 中 Maven 的
pom.xml, 用于描述项目的元信息,名称、版本等,更重要的是它指定了项目运行依赖的模块,下面就是本项目此文件的内容:
{ "name": "dunwoo-admin", "version": "1.0.0", "description": "Bootstrap 4
Theme", "author": "wskwbog", "license": "MIT", "private": true, "keywords": [],
"scripts": { "build": "webpack --progress --colors", "dev": "webpack-dev-server
--inline --devtool eval-source-map --progress", "start": "npm run dev" },
"devDependencies": { "@babel/core": "^7.2.2",
"@babel/plugin-proposal-object-rest-spread": "^7.3.2", "@babel/preset-env":
"^7.3.1", "autoprefixer": "^9.4.7", "babel-loader": "^8.0.6", "css-loader":
"^3.2.0", "node-sass": "^4.12.0", "postcss-loader": "^3.0.0", "sass-loader":
"^7.2.0", "style-loader": "^1.0.0", "webpack": "^4.39.2", "webpack-cli":
"^3.3.7", "webpack-dev-server": "^3.8.0", "mini-css-extract-plugin": "^0.8.0",
"clean-webpack-plugin": "^3.0.0" }, "dependencies": { "bootstrap": "^4.3.1",
"jquery": "^3.3.1", "popper.js": "^1.14.7" } }
其中关键配置的意义是:

* scripts: 配置不同功能脚本命令的缩写,可以使用 npm run build|dev 简单方便的调用
* devDependencies: 指定项目开发所需要的模块
* dependencies: 指定项目运行所依赖的模块
配置好 package.json 后就可以在当前目录运行 npm install 依赖的模块就会下载到当前目录的 node_modules 目录中。

在开始使用 Webpack 之前,还要进行一些配置,这也是比较麻烦的地方,本项目的 webpack.config.js 配置内容如下:
// 引入 node 相关模块 const path = require('path'); const MiniCssExtractPlugin =
require('mini-css-extract-plugin'); const { CleanWebpackPlugin } =
require('clean-webpack-plugin'); module.exports = { mode: 'development',
devtool: 'source-map', entry: { theme: './src/js/theme.js' // 入口文件 }, output: {
// 打包输出目录 path: path.resolve(__dirname, './dist/'), filename: 'js/[name].js' },
devServer: { // 本地开发服务器 contentBase: './dist/', host: '0.0.0.0', port: 3000,
writeToDisk: true }, module: { rules: [{ test: /(\.jsx|\.js)$/, // 正则匹配 .jsx 或
.js 后缀的文件 loader: 'babel-loader', exclude: /node_modules/ }, { test:
/\.(scss)$/, // 正则匹配 .scss 后缀的文件 use: [{ // loader: 'style-loader', // inject
CSS to page loader: MiniCssExtractPlugin.loader, options: { // publicPath:
'../', // hmr: process.env.NODE_ENV === 'development', }, }, { loader:
'css-loader', // translates CSS into CommonJS modules }, { loader:
'postcss-loader', // Run postcss actions options: { plugins: function () { //
postcss plugins, can be exported to postcss.config.js return [
require('autoprefixer') ]; } } }, { loader: 'sass-loader' // compiles Sass to
CSS }] }] }, plugins: [ new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:['js/*', 'css/*'] }), new MiniCssExtractPlugin({
filename: 'css/[name].css', chunkFilename: 'css/[id].css', }) ] }
接下来分析下各配置项的作用。

entry/output
entry: { theme: './src/js/theme.js' }, output: { path: path.resolve(__dirname,
'./dist/'), filename: 'js/[name].js' },
入口(entry)和出口(output)的配置比较简单,指定了从哪个模块开始构建以及将编译结果输出目的地。其中 **__dirname** 表示
webpack.config.js 所在的目录。

webpack-dev-server

通常开发的过程是:

* 修改 scss 样式
* 然后命令行运行 npm run build 编译
* 最后刷新页面看效果
这几步完全可以自动化,Webpack 就提供了一个本地开发 Web 服务器 webpack-dev-server,
它可以监听代码的改动并自动编译和发布,基本配置如下:
devServer: { contentBase: './dist/', // 资源根目录 host: '127.0.0.1', // 绑定主机 IP
port: 3000, // 监听端口 writeToDisk: true // 将编译结果写到磁盘 },
更多配置项可参考:https://webpack.js.org/configuration/dev-server/

接下来就是 Webpack 两个比较重要概念的配置, Loader 和 Plugin:

* Loader: 编译和转换模块源码,比如将 scss 编译成 css, 将 ES6 转为 JS, 将 JSX 文件转成 JS 文件等等
* Plugin: 用于解决 Loader 无法实现的功能,比如清理,打包优化和压缩等等
Babel

Bootstrap 4 使用 ES6 重写了所有的 JS 组件,而 Babel 就是一个 JavaScript 编译器,它可以将使用 ES6
语法编写的文件,转成浏览器兼容的 JS 文件。在 package.json 中与它相关的模块如下:

* @babel/core: Babel 编译的核心
* @babel/preset-env: 为每个环境预设的 Babel
* babel-loader: 结合使用 Babel 和 webpack 编译 JavaScript

* @babel/plugin-proposal-object-rest-spread: 支持 ES6 扩展运算符(...)
与把它相关的配置文件通常会放到一个名为 .babelrc.js 的文件中:
module.exports = { presets: [ [ '@babel/env', { loose: true, modules: false,
exclude: ['transform-typeof-symbol'] } ] ], plugins: [
'@babel/plugin-proposal-object-rest-spread' ] };
CSS 模块

Webpack 提供了两个 Loader 来处理样式,css-loader 和 style-loader,二者处理的任务不同:

* css-loader: 解析 @import 和 url() 方法,实现类似 import/require() 的功能
* style-loader: 将样式加入到页面中,与 css-loader 结合使用可以把样式嵌入到 webpack 打包后的 JS 文件中
CSS 预处理器比如 Sass 对原生 CSS 进行了扩展,添加了变量,函数等特性,使得 css 的编写更加灵活,Webpack 配置以下两个 Loader
后就能直接使用:

* sass-loader: 将 scss 编译成 css
* postcss-loader: 主要使用 autoprefixer 添加浏览器前缀
具体配置可查看上文的 webpack.config.js, 有一点需要注意的是: 高版本的 autoprefixer, 支持的浏览器配置通常放在
.browserslistrc 文件中。

mini-css-extract-plugin

将 CSS 提取为独立文件的插件,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,支持 CSS 和 SourceMaps 的按需加载,依赖
Webpack 4 以上的版本。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader:
MiniCssExtractPlugin.loader, options: { // 指定资源路径, 默认与 webpackOptions.output 相等
publicPath: '../', // 模块热加载相关配置 hmr: process.env.NODE_ENV === 'development', },
}, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({ // Options
similar to the same options in webpackOptions.output // all options are
optional filename: '[name].css', chunkFilename: '[id].css', ignoreOrder: false,
// Enable to remove warnings about conflicting order }), ], };
更多配置项可参考:https://webpack.js.org/plugins/mini-css-extract-plugin/

clean-webpack-plugin

Webpack 构建之前用于删除和清理构建文件夹的插件,这个插件有个属性 cleanOnceBeforeBuildPatterns
可以配置哪些文件和文件夹要删除,哪些不删除,一个简单的示例如下:
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports
= { plugins: [ new CleanWebpackPlugin({ // 只清理 js 和 css 目录中的文件
cleanOnceBeforeBuildPatterns:['js/*', 'css/*'] }), ], };
更多配置项可参考:https://www.npmjs.com/package/clean-webpack-plugin

Bootstrap 主题定制方法

定制 Bootstrap 4 主题有两个方法,一是直接修改源码,但这样后续不好升级;二是修改它提供的 SCSS
变量灵活定制,这样对源码没有侵入性,可以在不触及核心文件的情况下完全重新设计 Bootstrap 4 的样式。项目文件的基本结构如下:
dunwoo-admin/ ├── .babelrc.js ├── .browserslistrc ├── .gitignore ├──
package.json ├── webpack.config.js ├── README.md ├── src/ │ ├── scss/ │ │ ├──
base/ │ │ ├── pages/ │ │ ├── partials/ │ │ ├── utilities/ │ │ ├── vendor/ │ │
└── _theme.scss │ ├── js/ │ │ ├── modules/ │ │ ├── vendor/ │ │ └── theme.js │
│── fonts/ │ └── img/ └── dist/ ├── css/ │ └── theme.css ├── js/ │ └── theme.js
├── img/ ├── fonts/ └── libs/
其中主要的 Sass 文件就是 src/scss/_theme.scss:
@charset "utf-8"; // 覆盖原设计样式的变量 @import "base/variables-theme"; // bootstrap
核心源码 @import "../../node_modules/bootstrap/scss/bootstrap"; // 自定义组件的样式 @import
"base/variables"; @import "base/general"; @import "partials/menubar"; @import
"partials/navbar"; @import "partials/card"; @import "partials/widget"; @import
"partials/timeline"; @import "pages/signin"; @import "utilities/utilities";
一个简单修改主题颜色变量的方法是:
$theme-colors: ( "primary": #2c7be5, "secondary": #95aac9, "success": #00d97e,
"info": #39afd1, "warning": #f6c343, "danger": #e63757, "light": #f8f9fa,
"dark": #3b506c );
在项目根目录执行 npm run build 就能在页面看到修改结果。

小结

本文只是对 webpack 简单的使用,对于前端目前也正在学习,如有错误欢迎指出交流。

源码可从 GitHub 链接下载,https://github.com/dwosc/dunwoo-admin

或者关注微信公众号「顿悟源码」回复关键词「Bootstrap」 获取百度网盘下载链接。

主题将会不断更新优化,欢迎关注!