专题11: 将js/css打包进html,并配置 devServer
luoxue-victor opened this issue · comments
课题 2:搭建可插拔的开发环境跟生产环境
本章提要:
- 需要哪些包?
- 构建开发环境(devServer)
- 构建生产环境
- 自动生成 html
- 提取 css
需要哪些包?
package.json
{
"scripts": {
"dev": "cross-env NODE_ENV=development node build/dev.js",
"build": "cross-env NODE_ENV=production node build/build.js"
},
"dependencies": {
"@commitlint/config-conventional": "^8.2.0",
"cross-env": "^6.0.3",
"css-loader": "^3.2.0",
"cssnano": "^4.1.10",
"ora": "^4.0.3",
"rimraf": "^3.0.0",
"webpack": "^4.41.2"
},
"devDependencies": {
"extract-text-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"vue-cli-plugin-commitlint": "^1.0.4",
"webpack-chain": "^6.0.0",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
}
}
目录
|-- build
|-- base.js // 公共部分
|-- build.js
|-- dev.js
|-- config
|-- base.js // 基础配置
|-- css.js // css 配置
|-- HtmlWebpackPlugin.js // html 配置
|-- MiniCssExtractPlugin.js // 提取css
|-- public // 公共资源
|-- index.html // html 模版
|-- src // 开发目录
|-- style
|---- index.css
|-- main.js // 主入口
实现可插拔配置
build/base.js
const { findSync } = require('../lib');
const Config = require('webpack-chain');
const config = new Config();
const files = findSync('config');
const path = require('path');
const resolve = p => {
return path.join(process.cwd(), p);
};
module.exports = () => {
const map = new Map();
files.map(_ => {
const name = _.split('/')
.pop()
.replace('.js', '');
return map.set(name, require(_)(config, resolve));
});
map.forEach((v, key) => {
v();
});
return config;
};
生产环境搭建
build/build.js
const rimraf = require('rimraf');
const ora = require('ora');
const chalk = require('chalk');
const path = require('path');
// 删除 dist 目录
rimraf.sync(path.join(process.cwd(), 'dist'));
const config = require('./base')();
const webpack = require('webpack');
const spinner = ora('开始构建项目...');
spinner.start();
webpack(config.toConfig(), function(err, stats) {
spinner.stop();
if (err) throw err;
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n'
);
if (stats.hasErrors()) {
console.log(chalk.red('构建失败\n'));
process.exit(1);
}
console.log(chalk.cyan('build完成\n'));
});
开发环境搭建
build/dev.js
const config = require('./base')();
const webpack = require('webpack');
const chalk = require('chalk');
const WebpackDevServer = require('webpack-dev-server');
const port = 8080;
const publicPath = '/common/';
config.devServer
.quiet(true)
.hot(true)
.https(false)
.disableHostCheck(true)
.publicPath(publicPath)
.clientLogLevel('none');
const compiler = webpack(config.toConfig());
// 拿到 devServer 参数
const chainDevServer = compiler.options.devServer;
const server = new WebpackDevServer(
compiler,
Object.assign(chainDevServer, {})
);
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, () => {
server.close(() => {
process.exit(0);
});
});
});
// 监听端口
server.listen(port);
new Promise(() => {
compiler.hooks.done.tap('dev', stats => {
const empty = ' ';
const common = `App running at:
- Local: http://127.0.0.1:${port}${publicPath}\n`;
console.log(chalk.cyan('\n' + empty + common));
});
});
提取 css
config/css.js
module.exports = (config, resolve) => {
return (lang, test) => {
const baseRule = config.module.rule(lang).test(test);
const normalRule = baseRule.oneOf('normal');
applyLoaders(normalRule);
function applyLoaders(rule) {
rule
.use('extract-css-loader')
.loader(require('mini-css-extract-plugin').loader)
.options({
publicPath: './'
});
rule
.use('css-loader')
.loader('css-loader')
.options({});
}
};
};
自动生成 html
config/HtmlWebpackPlugin.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = (config, resolve) => {
return () => {
config.plugin('html').use(HtmlWebpackPlugin, [
{
template: 'public/index.html'
}
]);
};
};
css 提取插件
config/MiniCssExtractPlugin.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (config, resolve) => {
return () => {
config
.oneOf('normal')
.plugin('mini-css-extract')
.use(MiniCssExtractPlugin);
};
};
测试文件
测试 html 模板
public/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>learn_webpack</title>
<body></body>
</html>
测试 css 模板
src/style/index.css
.test {
width: 200px;
height: 200px;
color: red;
background-color: orange;
}
程序入口
src/main.js
require('./style/index.css');
const h2 = document.createElement('h2');
h2.className = 'test';
h2.innerText = 'test';
document.body.append(h2);