之前讲过webpack4中的runtimeChunk配置:webpack4中的 optimization.runtimeChunk,我们知道了runtimeChunk分离的是运行时的模块,它和业务无关,主要包含webpack的一些定义以及从主模块分离出去模块的信息。它的代码量一般比较小,且比较容易变化,为了优化代码,可以考虑将runtimeChunk做成内联的,也就是将runtimeChunk部分的代码直接写入index.html。

HtmlWebpackPlugin

我们先看个普通的vue项目,并且配置了runtimeChunk:

/*---App.vue---*/
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>
/*---About.vue---*/
<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>
/*---router.js---*/
Vue.use(VueRouter)
const routes = [
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/About.vue')
  }
]

配置vue.config.js:

configureWebpack: {
	optimization: {
		runtimeChunk:{
			name:()=>'aaa'
		},
	},
}

打包结果如下:

aaa.***.js是分离出的runtimeChunk,那么如何将它的内容直接写入html中呢?重新配置vue.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineSourcePlugin = require('html-webpack-inline-source-plugin');
configureWebpack: {
	optimization: {
		runtimeChunk:{
			name:()=>'aaa'
		},
	},
	plugins: [
		new HtmlWebpackPlugin({
			// Inline all files which names start with “aaa” and end with “.js”.
			// That’s the default naming of runtime chunks
			inlineSource: 'aaa.+\\.js',
		}),
		// This plugin enables the “inlineSource” option
		new InlineSourcePlugin(),
	]
}

重新打包,我们可以看到runtimeChunk已经写入index.html了:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>Webpack App</title>
		<link href="/css/app.7edf2138.css" rel="stylesheet">
	</head>

	<body>
		<script type="text/javascript">
			(function(e) {
				function r(r) {
					for(var n, a, i = r[0], c = r[1], l = r[2], f = 0, s = []; f < i.length; f++) a = i[f], Object.prototype.hasOwnProperty.call(o, a) && o[a] && s.push(o[a][0]), o[a] = 0;
					for(n in c) Object.prototype.hasOwnProperty.call(c, n) && (e[n] = c[n]);
					p && p(r);
					while(s.length) s.shift()();
					return u.push.apply(u, l || []), t()
				}

				function t() {
					for(var e, r = 0; r < u.length; r++) {
						for(var t = u[r], n = !0, a = 1; a < t.length; a++) {
							var c = t[a];
							0 !== o[c] && (n = !1)
						}
						n && (u.splice(r--, 1), e = i(i.s = t[0]))
					}
					return e
				}
				var n = {},
					o = {
						aaa: 0
					},
					u = [];

				function a(e) {
					return i.p + "js/" + ({
						about: "about"
					}[e] || e) + "." + {
						about: "b55882bc"
					}[e] + ".js"
				}

				function i(r) {
					if(n[r]) return n[r].exports;
					var t = n[r] = {
						i: r,
						l: !1,
						exports: {}
					};
					return e[r].call(t.exports, t, t.exports, i), t.l = !0, t.exports
				}
				i.e = function(e) {
					var r = [],
						t = o[e];
					if(0 !== t)
						if(t) r.push(t[2]);
						else {
							var n = new Promise((function(r, n) {
								t = o[e] = [r, n]
							}));
							r.push(t[2] = n);
							var u, c = document.createElement("script");
							c.charset = "utf-8", c.timeout = 120, i.nc && c.setAttribute("nonce", i.nc), c.src = a(e);
							var l = new Error;
							u = function(r) {
								c.onerror = c.onload = null, clearTimeout(f);
								var t = o[e];
								if(0 !== t) {
									if(t) {
										var n = r && ("load" === r.type ? "missing" : r.type),
											u = r && r.target && r.target.src;
										l.message = "Loading chunk " + e + " failed.\n(" + n + ": " + u + ")", l.name = "ChunkLoadError", l.type = n, l.request = u, t[1](l)
									}
									o[e] = void 0
								}
							};
							var f = setTimeout((function() {
								u({
									type: "timeout",
									target: c
								})
							}), 12e4);
							c.onerror = c.onload = u, document.head.appendChild(c)
						}
					return Promise.all(r)
				}, i.m = e, i.c = n, i.d = function(e, r, t) {
					i.o(e, r) || Object.defineProperty(e, r, {
						enumerable: !0,
						get: t
					})
				}, i.r = function(e) {
					"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
						value: "Module"
					}), Object.defineProperty(e, "__esModule", {
						value: !0
					})
				}, i.t = function(e, r) {
					if(1 & r && (e = i(e)), 8 & r) return e;
					if(4 & r && "object" === typeof e && e && e.__esModule) return e;
					var t = Object.create(null);
					if(i.r(t), Object.defineProperty(t, "default", {
							enumerable: !0,
							value: e
						}), 2 & r && "string" != typeof e)
						for(var n in e) i.d(t, n, function(r) {
							return e[r]
						}.bind(null, n));
					return t
				}, i.n = function(e) {
					var r = e && e.__esModule ? function() {
						return e["default"]
					} : function() {
						return e
					};
					return i.d(r, "a", r), r
				}, i.o = function(e, r) {
					return Object.prototype.hasOwnProperty.call(e, r)
				}, i.p = "/", i.oe = function(e) {
					throw console.error(e), e
				};
				var c = window["webpackJsonp"] = window["webpackJsonp"] || [],
					l = c.push.bind(c);
				c.push = r, c = c.slice();
				for(var f = 0; f < c.length; f++) r(c[f]);
				var p = l;
				t()
			})([]);
			//# sourceMappingURL=/js/aaa.d6f2d2a1.js.map
		</script>
		<script type="text/javascript" src="/js/chunk-vendors.13cf26cb.js"></script>
		<script type="text/javascript" src="/js/app.fb7ad43f.js"></script>
	</body>

</html>

ManifestPlugin

上面那种是通过webpack打包工具直接打包到index.html,还有一种更适合后端的,我们可以将打包的后的文件生成一个清单,重新设置vue.config.js:

const ManifestPlugin = require('webpack-manifest-plugin');
configureWebpack: {
	optimization: {
		runtimeChunk:{
			name:()=>'aaa'
		},
	},
	plugins: [
	        new ManifestPlugin()
	]
}

打包,我们得到了manifest.json:

{
  "aaa.js": "/js/aaa.a9193722.js",
  "aaa.js.map": "/js/aaa.a9193722.js.map",
  "about.js": "/js/about.eeb8a4cc.js",
  "about.js.map": "/js/about.eeb8a4cc.js.map",
  "app.css": "/css/app.7edf2138.css",
  "app.js": "/js/app.b5ae3d68.js",
  "app.css.map": "/css/app.7edf2138.css.map",
  "app.js.map": "/js/app.b5ae3d68.js.map",
  "chunk-vendors.js": "/js/chunk-vendors.13cf26cb.js",
  "chunk-vendors.js.map": "/js/chunk-vendors.13cf26cb.js.map",
  "favicon.ico": "/favicon.ico",
  "img/logo.png": "/img/logo.82b9c7a5.png",
  "index.html": "/index.html"
}

manifest.json文件目录如下:

有了这份清单,我们就可以得到文件的真实名称了(含hash),下面代码可以参考,如何在服务端得到文件内容,并渲染到index.html:

// server.js
const fs = require('fs');
const manifest = require('./manifest.json');

const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8');

app.get('/', (req, res) => {
  res.send(`
    …
    <script>${runtimeContent}</script>
    …
  `);
});
回到顶部
我要评论

所有评论

返回
邮箱:
绑定
取消
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

邮箱:
绑定邮箱后,若有回复,会邮件通知。
提交
还可以输入500个字