# 静态页面(模板解析)

前言

模板指的是每个 page 下的 html 模板文件,vue 创建项目时,默认使用单页应用配置,模板文件的作用主要用于 webpack 中 html-webpack-plugin 插件的配置,其会根据模板文件生产一个编译后的 html 文件并自动加入携带 hash 的脚本和样式

# 1.模板配置

# 1.1 单模板配置






 
 
 
 
 
 
 




/* webpack 配置文件 */
const HtmlWebpackPlugin = require('html-webpack-plugin') // 安装并引用插件
module.exports = {
    ...
    plugins: [
        new HtmlWebpackPlugin({
            title: 'My Page', // 生成 html 中的 title
            filename: 'demo.html', // 生成 html 的文件名
            template: 'xxx/xxx/demo.html', // 模板路径
            chunks: ['manifest', 'vendor', 'demo'], // 所要包含的模块
            inject: true, // 是否注入资源
        })
    ]
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 1.2 多模板配置

  • 抽离公共配置
/* utils.js */
// 多页面输出配置
// 与上面的多页面入口配置相同,读取 page 文件夹下的对应的 html 后缀文件,然后放入数组中
exports.htmlPlugin = (configs) => {
  let entryHtml = glob.sync(PAGE_PATH + "/*/*.html")
  let arr = []
  entryHtml.forEach((filePath) => {
    let filename = filePath.substring(
      filePath.lastIndexOf("/") + 1,
      filePath.lastIndexOf(".")
    )
    let conf = {
      template: filePath, // 模板路径
      filename: filename + ".html", // 生成 html 的文件名
      chunks: ["manifest", "vendor", filename],
      inject: true,
    }
    // 如果有自定义配置可以进行 merge
    if (configs) {
      conf = merge(conf, configs)
    }
    // 针对生产环境配置
    if (process.env.NODE_ENV === "production") {
      conf = merge(conf, {
        minify: {
          removeComments: true, // 删除 html 中的注释代码
          collapseWhitespace: true, // 删除 html 中的空白符
          // removeAttributeQuotes: true // 删除 html 元素中属性的引号
        },
        chunksSortMode: "manual", // 按 manual 的顺序引入
      })
    }
    arr.push(new HtmlWebpackPlugin(conf))
  })
  return arr
}
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

以上我们仍然是使用 glob 读取所有模板文件,然后将其遍历并设置每个模板的 config,同时针对一些自定义配置和生产环境的配置进行了 merge 处理,其中自定义配置的功能我会在下节进行介绍,这里介绍一下生产环境下 minify 配置的作用:将 html-minifier 的选项作为对象来缩小输出

html-minifier (opens new window) 是一款用于缩小 html 文件大小的工具,其有很多配置项功能,包括上述所列举的常用的删除注释、空白、引号等。

  • 配置多模板配置
/* vue.config.js */
const utils = require('./build/utils')
module.exports = {
    ...
    configureWebpack: config => {
        config.entry = utils.getEntries() // 直接覆盖 entry 配置
        return {
            plugins: [...utils.htmlPlugin()] // 使用 return 一个对象会通过 webpack-merge 进行合并,plugins 不会置空
        }
    },
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12

这时候我们运行命令 yarn build 后你会发现 dist 目录下生成了 3 个 html 文件,分别是 index.html、page1.html 和 page2.html。

# 2. 模板渲染

总结

基于以上多页应用的认识,多页应用典型场景:pc 端扫码登录页面,主页面用 vue 开发,移动端 h5 页面新建一个 html 文件,用原生 js 开发;配置多页面,扫码后手机端进入项目写好的 h5 页面。

# 2.1. 模板渲染

这里所说的模板渲染是在我们的 html 模板文件中使用 html-webpack-plugin 提供的 default template (opens new window) 语法进行模板编写,比如:








 
 
 
 




 
 
 
 
 
 
 



<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>模板</title>
    <% for (var chunk in htmlWebpackPlugin.files.css) { %> <%
    if(htmlWebpackPlugin.files.css[chunk]) {%>
    <link href="<%= htmlWebpackPlugin.files.css[chunk] %>" rel="stylesheet" />
    <%}%> <% } %>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <% for (var chunk in htmlWebpackPlugin.files.js) { %> <%
    if(htmlWebpackPlugin.files.js[chunk]) {%>
    <script
      type="text/javascript"
      src="<%= htmlWebpackPlugin.files.js[chunk] %>"
    ></script>
    <%}%> <% } %>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • 我们通过配置 htmlWebpackPlugin.files 可以获取打包输出的 js 及 css 文件路径,包括入口文件路径等
"htmlWebpackPlugin": {
    "files": {
        "css": [ "main.css" ],
        "js": [ "assets/head_bundle.js", "assets/main_bundle.js"],
        "chunks": {
            "head": {
                "entry": "assets/head_bundle.js",
                "css": [ "main.css" ]
            },
            "main": {
                "entry": "assets/main_bundle.js",
                "css": []
            },
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 需要注意的是如果你在模板中编写了插入对应 js 及 css 的语法,你需要设置 inject 的值为 false 来关闭资源的自动注入:
/* utils.js */
...
let conf = {
    entry: filePath, // page 的入口
    template: filePath, // 模板路径
    filename: filename + '.html', // 生成 html 的文件名
    chunks: ['manifest', 'vendor',  filename],
    inject: false, // 关闭资源自动注入
}
...
1
2
3
4
5
6
7
8
9
10

# 2.2. 自定义配置

如果遇到需要根据不同环境来引入不同资源,同时不同模板间的配置还可能不一样的需求情况的话,我们使用自定义配置会比较方便。比如我们需要在生产环境模板中引入第三方统计脚本

/* vue.config.js */
module.exports = {
    ...
    pages: utils.setPages({
        addScript() {
            if (process.env.NODE_ENV === 'production') {
                return `
                    <script src="https://s95.cnzz.com/z_stat.php?id=xxx&web_id=xxx" language="JavaScript"></script>
                `
            }
            return ''
        }
    }),
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

然后在页面模板中通过 htmlWebpackPlugin.options 获取自定义配置对象并进行输出:

<% if(htmlWebpackPlugin.options.addScript){ %>
    <%= htmlWebpackPlugin.options.addScript() %>
<%}%>
1
2
3

同时你也可以针对个别模板进行配置,比如我想只在 Index 单页中添加统计脚本,在 Page1 单页中添加其他脚本,那么你可以给 addScript 传入标识符来进行判断输出,比如:

<% if(htmlWebpackPlugin.options.addScript){ %>
    <%= htmlWebpackPlugin.options.addScript('index') %>
<%}%>
1
2
3

同时为 addScript 方法添加参数 from:

addScript(from) {
    if (process.env.NODE_ENV === 'production') {
        let url = "https://xxx";
        if (from === 'index') {
            url = "https://s95.cnzz.com/z_stat.php?id=xxx&web_id=xxx";
        }
        return `
            <script src=${url} language="JavaScript"></script>
        `
    }
    return ''
}
1
2
3
4
5
6
7
8
9
10
11
12

这样我们就完成了自定义配置中的模板渲染功能。当然根据实际项目需求你的自定义配置项可能会更加复杂和灵活。

总结

了解 vue 项目创建过程以及其目录结构,在开发中需要注意的地方,能够更好地规范前端开发