为单页应用生成HTML
引入问题
以上所有的栗子都是只输出一个bundle.js文件,所以手写了index.html文件取引入bundle.js文件,才能让应用再项目中运行起来,但是实际的项目比较复杂,一个页面会有很多资源要加载,我们会发现最终发布到线上的代码被内嵌了一些内容,部分文件名称打上根据文件内容算出的hash值,并且加载这些文件的url地址也被正常注入HTML中,所以手写index.html不现实,所以如何自动化盛昌符合要求的index.html文件
解决方案
推荐解决以上问题的插件:web-webpacj-plugin 1、修改Webpack配置文件如下
const path = require('path');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifuPlugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const DefinePlugin = require('webpack/lob/DefinePlugin');
const { WebPlugin } = require('web-webpack-plugin');
module.exports = {
entry: {
app: './main.js' // app的js执行入口文件
},
output: {
filename: '[name]_[chunkhash:8].js', // 为输出的文件名称加上Hash值
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
// 排除node_modules目录下文件
// 该目录下的文件都采用了es5语法,没必要再使用babel转换
exclude: path.resolve(__dirname, 'node_modules'),
},
{
test: /\.css/, //增加对css文件的支持
// 提取出Chunk中CSS代码到单独的文件中
use: ExtractTextPlugin.extract({
use: ['css-loader?minimize'] //压缩css代码
}),
},
]
},
plugins: [
// 使用本文的主角Webplugin,一个WebPlugin对应一个Html文件
new WebPlugin({
template: './template.html', // HTML模版文件所在的文件路径
filename: 'index.html' // 输出的HTML文件的名称
}),
new ExtractTextPlugin({
filename: `[name]_[contenthash:8].css`, // 为输出的css文件名加上一个hash值
}),
new DefinePlugin({
// 定义NODE_ENV环境变量为production,以去除源码中只有开发时才需要的部分
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
// 压缩输出的js代码
new UglifyJsPlugin({
// 紧凑的输出
beautify: false,
// 删除所有注释
comments: false,
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有`console`语句,可以兼容IE浏览器
drop_console: true,
// 内嵌已定义但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
})
]
}
其中template: './template.htm'所指的模版文件内容是
<html>
<head>
<meta charset="UTF-8">
<!--注入Chunk app中的css代码-->
<link rel="stylesheet" href="app?_inline">
<!--注入google_analytics中的js代码-->
<script src="./google_analytics.js?_inline"></script>
<!--异步加载XXX-->
<script src="XXX" async></script>
</head>
<body>
<div id="app"></div>
<!--导入Chunk中的js代码-->
<script src="app"></script>
<!--XXX-->
<div id="xxx_thread"></div>
</body>
</html>
该文件描述了哪些文件以某种方式加入到输出的html中
<link rel="stylesheet" href="app?_inline">是按照正常引入css文件一样的语法引入webpack生产的代码,href属性中的app?_inline可以分为两部分,app表示css代码来自名叫app的chunk,_inline表示这个标签需要被嵌入到这个标签所在位置
<script src="./google_analytics.js?_inline"></script>表示js代码来自相对于当前模版文件template.html的本地文件./google_analytics.js,_inline表示这些代码要被内嵌到这个标签所在的位置
总结:资源链接url问号前面的内容表示资源来自哪里,后面的内容表示这些资源的注入方式
该插件出克支持_inline属性,还支持
- _dist:只有在生产环境下才引入该资源
- _dev:只有在开发环境下才引入该资源
- _ie:只有在IE浏览器下才引入该资源
管理多个单页应用
引入问题
我们不能手动管理多个但页面应用的生成吧!!!不能吧,不能吧,当然不能,还能不能好好维护了 按照单页面应用的构建思路来说,我们如果手动维护 首先就要为每个单页应用添加配置
new WebPlugin({
template: './template.html', // HTML模版文件所在的文件路径
filename: 'login.html' // 输出的HTML文件的名称
}),
再改入口文件
entry: {
index: './pages/index/index.js',
login: './pages/login/index.js'
},
好累啊,每加一个页面就要重新配置一遍,这不是我们咸鱼的性格!!!上解决方案
解决方案
使用AutoWebPlugin来解决以上问题
1、先看看目录要求
|-- pages
|-- index
|-- index.js
|-- index.css
|-- login
|-- index.js
|-- index.css
|-- common.css
|-- google_analytics.js
|-- template.html
|-- webpack.config.js
从目录看出以下要求 1、所有单页应用都需要放到一个目录下,如pages 2、一个单页应用对应一个单独的文件夹 3、每个单页应用的目录下都有一个index.js文件作为入口执行文件
2、修改Webpack配置文件
const autoWebPlugin = new AutoWebPlugin('pages', {
template:'./template.html', // HTML模版文件所在目录
postEntrys: ['./common.css'], // 所有页面都依赖这份通用的css样式文件
// 提取出所有页面的公共代码
commonsChunk: {
name: 'common', // 提取出公共代码Chunk的名称
}
});
module.exports = {
// AutoWebPlugin会为寻找到的所有单页应用生成对用的入口配置
// autoWebPlugin.entry方法可以获取所有由AutoWebPlugin生成的入口配置
entry: autoWebPlugin.entry({
// 这里可以加入额外需要的Chunk入口
}),
plugins: [
autoWebPlugin,
]
}
3、template.html文件大致如下
<html>
<head>
<meta charset="UTF-8">
<!--在这里注入该页面所依赖单没有手动导入的CSS-->
<!--STYLE-->
<!--注入google_analytics中的js代码-->
<script src="./google_analytics.js?_inline"></script>
<!--异步加载XXX-->
<script src="XXX" async></script>
</head>
<body>
<div id="app"></div>
<!--导入Chunk中的js代码-->
<!--在这里注入该页面所依赖但没有手动导入的js-->
<!--SCRIPT-->
<!--XXX-->
<div id="xxx_thread"></div>
</body>
</html>
<!--SCRIPT-->和<!--STYLE-->是啥?因为Chunk不固定,不能写死,它保证了该页面所依赖的资源都会被注入生成的HTML模版里