webpack系列-pug实战
Pug(jade)
模板引擎。类似于JSP、FreeMarker之类Java相关的模板引擎。Pug(原称是jade)是Nodejs相关的模板引擎,可以和Express进行集成。
类似的Nodejs相关的模板引擎:ejs、art-template、doT、Handlebars、Mustache等
模板引擎通常都是有后端搭配进行数据传输,但是有的时候只需要静态页面不需要后端时,类似Java的模板引擎就不好用了。可以在node环境下使用模板引擎可以生成静态页面后发布。
模板引擎的好处在于可以将重复的代码提出来进行模块化,可以进行灵活的嵌入、继承、扩展等,降低后期维护难度和代码修改工作量。
主要问题在于数据传值部分。
- 可以将数据写在模板里定义常量进行数据取值,但是灵活性不高,如果不同的网站数据相同的样式,需要重新创建文件定义常量。
- 可以将数据写在JSON文档中,可以进行单文件或多文件进行命令行编译。
- 可以使用webpack进行打包,补充兼容、压缩和优化代码,但是难点在于webpack配置和pug配置,如特殊需要,可能需要编写插件或loader。
实例代码:https://github.com/Datura35422/pug-demo/tree/master/website
项目配置
package.json
{
"name": "website",
"version": "1.0.0",
"description": "",
"dependencies": {
"jquery": "^3.6.0"
},
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"autoprefixer": "^10.2.5",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^8.0.0",
"css-loader": "^5.1.3",
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"file-loader": "^6.2.0",
"html-webpack-injector": "^1.1.4",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.3.9",
"postcss-loader": "^5.2.0",
"pug-loader": "^2.4.0",
"url-loader": "^4.1.1",
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.7.3"
},
"scripts": {
"build": "npx webpack --config ./build/webpack.build.conf.js",
"debug": "node --inspect --inspect-brk webpack --config ./build/webpack.build.conf.js",
"dev": "npx webpack-dev-server --open --config ./build/webpack.dev.conf.js"
},
"author": "",
"license": "ISC",
"browserslist": [
"> 1%",
"last 3 version"
]
}
webpack 配置
webpack.base.conf.js
// reference https://github.com/vedees/webpack-template-pug & https://github.com/vedees/webpack-template
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackInjector = require('html-webpack-injector');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const dataJson = require('../src/data/home.json')
// Main const
const PATHS = {
// Path to main app dir
src: path.join(__dirname, '../src'),
// Path to Output dir
dist: path.join(__dirname, '../dist')
}
// Pages const for HtmlWebpackPlugin
const PAGES_DIR = `${PATHS.src}/pages/`
const PAGES = fs.readdirSync(PAGES_DIR).filter(fileName => fileName.endsWith('.pug'))
module.exports = {
// BASE config
externals: {
paths: PATHS // webpack.dev.conf 中 devServer中会使用
},
entry: {
index: `${PATHS.src}/js/index.js`,
index_head: `${PATHS.src}/js/judegDevice.js`
},
output: {
filename: `js/[name].[fullhash].js`,
path: PATHS.dist,
publicPath: './'
},
// 优化
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendors',
test: /node_modules/,
chunks: 'all',
enforce: true
}
}
}
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({ // 压缩优化css
filename: `css/[name].[fullhash].css`
}),
// 处理静态文件 将静态引入的文件复制到目标目录下 要与html中的文件引用一样 不然HtmlWebpackPlugin会编译出错
new CopyWebpackPlugin({
patterns: [
{
from: `src/imgs`,
to: `imgs`
},
{
from: `src/favicon.ico`,
to: `favicon.ico`
}
]
}),
// 自动加载模块
new webpack.ProvidePlugin({ // 其他js文件中使用jquery 进行自动导入
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery'
}),
// Automatic creation any html pages (Don't forget to RERUN dev server)
// see more: https://github.com/vedees/webpack-template/blob/master/README.md#create-another-html-files
// best way to create pages: https://github.com/vedees/webpack-template/blob/master/README.md#third-method-best
...PAGES.map(page => {
return new HtmlWebpackPlugin({
minify: 'production', // 压缩
template: `${PAGES_DIR}/${page}`,
filename: `${page.replace(/\.pug/,'.html')}`,
chunks: ['index', 'index_head'],
data: dataJson
// chunksConfig: { // Added option
// async: ["index_head"],
// defer: ["index"]
// }
})
}),
new HtmlWebpackInjector(), // js分开注入
],
stats: {
children: true
},
module: {
rules: [
{
test: /\.pug$/,
use: [
{
loader: 'pug-loader',
options: { // 配置参考 pug api:https://pugjs.org/zh-cn/api/reference.html
pretty: true, // 不压缩html
self: true // 局部变量
}
}
]
},
{
test: /\.js$/,
exclude: '/node_modules/',
use: ['babel-loader']
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: 'url-loader', // 处理js、css中出现的img
options: {
// 为css内的图片、文件等外部资源指定一个自定义的公共路径
name(resourcePath) { // 替换css中的文件名
console.log('resourcePath: ', resourcePath)
let url = path.relative(`${PATHS.src}/imgs/`, path.dirname(resourcePath)) + '/[name].[ext]'
url = url.replace('\\', '/')
return url;
},
outputPath: 'imgs', // 输出目录, 如果配置好路径的话可以不用配置
limit: 8190
}
}
],
type: 'javascript/auto' // webpack v5
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// 将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
publicPath: (resourcePath) => {
return path.relative(path.dirname(resourcePath), `${PATHS.src}/`) + '/';
}
}
},
'css-loader',
'postcss-loader'
]
}
]
}
};
webpack.dev.conf.js
const webpack = require('webpack')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const devWebpackConfig = merge(baseWebpackConfig, {
// DEV config
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: baseWebpackConfig.externals.paths.dist, // 且仅在使用静态资源的时候配置
port: 8081,
open: true,
hot: true,
hotOnly: true, // 热更新
// historyApiFallback: true, // 响应html内容
overlay: { // 编译器警告
warnings: true,
errors: true
}
},
plugins: [
new webpack.SourceMapDevToolPlugin({
filename: '[file].map'
})
]
})
module.exports = new Promise((resolve, reject) => {
resolve(devWebpackConfig)
})
webpack.build.conf.js
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const buildWebpackConfig = merge(baseWebpackConfig, {
// BUILD config
mode: 'production',
plugins: []
})
module.exports = new Promise((resolve, reject) => {
resolve(buildWebpackConfig)
})
其他配置
postcss.config.js
// autoprefixer - https://github.com/postcss/autoprefixer
// css-mqpacker - https://github.com/hail2u/node-css-mqpacker
// cssnano - https://github.com/hail2u/node-css-mqpacker
// npm install postcss-loader autoprefixer css-mqpacker cssnano --save-dev
module.exports = {
plugins: [
require('autoprefixer'),
require('css-mqpacker'),
require('cssnano')({
preset: [
'default',
{
discardComments: {
removeAll: true
}
}
]
})
]
}
.babelrc
{
"presets": [
"@babel/preset-env"
]
}