mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-08 17:37:24 +08:00
181 lines
7.5 KiB
JavaScript
181 lines
7.5 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.createBuildHtmlPlugin = void 0;
|
|
const path_1 = __importDefault(require("path"));
|
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
const magic_string_1 = __importDefault(require("magic-string"));
|
|
const utils_1 = require("../utils");
|
|
const buildPluginAsset_1 = require("./buildPluginAsset");
|
|
exports.createBuildHtmlPlugin = async (root, indexPath, publicBasePath, assetsDir, inlineLimit, resolver, shouldPreload, config) => {
|
|
if (!fs_extra_1.default.existsSync(indexPath)) {
|
|
return {
|
|
renderIndex: () => '',
|
|
htmlPlugin: null
|
|
};
|
|
}
|
|
const rawHtml = await fs_extra_1.default.readFile(indexPath, 'utf-8');
|
|
const preprocessedHtml = await utils_1.transformIndexHtml(rawHtml, config.indexHtmlTransforms, 'pre', true);
|
|
const assets = new Map();
|
|
let { html: processedHtml, js } = await compileHtml(root, preprocessedHtml, publicBasePath, assetsDir, inlineLimit, resolver, assets);
|
|
const htmlPlugin = {
|
|
name: 'vite:html',
|
|
async load(id) {
|
|
if (id === indexPath) {
|
|
return js;
|
|
}
|
|
},
|
|
generateBundle(_options, bundle) {
|
|
buildPluginAsset_1.registerAssets(assets, bundle);
|
|
}
|
|
};
|
|
const injectCSS = (html, filename) => {
|
|
const tag = `<link rel="stylesheet" href="${publicBasePath}${path_1.default.posix.join(assetsDir, filename)}">`;
|
|
if (/<\/head>/.test(html)) {
|
|
return html.replace(/<\/head>/, `${tag}\n</head>`);
|
|
}
|
|
else {
|
|
return tag + '\n' + html;
|
|
}
|
|
};
|
|
const injectScript = (html, filename) => {
|
|
filename = utils_1.isExternalUrl(filename)
|
|
? filename
|
|
: `${publicBasePath}${path_1.default.posix.join(assetsDir, filename)}`;
|
|
const tag = `<script type="module" src="${filename}"></script>`;
|
|
if (/<\/head>/.test(html)) {
|
|
return html.replace(/<\/head>/, `${tag}\n</head>`);
|
|
}
|
|
else {
|
|
return html + '\n' + tag;
|
|
}
|
|
};
|
|
const injectPreload = (html, filename) => {
|
|
filename = utils_1.isExternalUrl(filename)
|
|
? filename
|
|
: `${publicBasePath}${path_1.default.posix.join(assetsDir, filename)}`;
|
|
const tag = `<link rel="modulepreload" href="${filename}" />`;
|
|
if (/<\/head>/.test(html)) {
|
|
return html.replace(/<\/head>/, `${tag}\n</head>`);
|
|
}
|
|
else {
|
|
return tag + '\n' + html;
|
|
}
|
|
};
|
|
const renderIndex = async (bundleOutput) => {
|
|
let result = processedHtml;
|
|
for (const chunk of bundleOutput) {
|
|
if (chunk.type === 'chunk') {
|
|
if (chunk.isEntry) {
|
|
// js entry chunk
|
|
result = injectScript(result, chunk.fileName);
|
|
}
|
|
else if (shouldPreload && shouldPreload(chunk)) {
|
|
// async preloaded chunk
|
|
result = injectPreload(result, chunk.fileName);
|
|
}
|
|
}
|
|
else {
|
|
// imported css chunks
|
|
if (chunk.fileName.endsWith('.css') &&
|
|
chunk.source &&
|
|
!assets.has(chunk.fileName)) {
|
|
result = injectCSS(result, chunk.fileName);
|
|
}
|
|
}
|
|
}
|
|
return await utils_1.transformIndexHtml(result, config.indexHtmlTransforms, 'post', true);
|
|
};
|
|
return {
|
|
renderIndex,
|
|
htmlPlugin
|
|
};
|
|
};
|
|
// this extends the config in @vue/compiler-sfc with <link href>
|
|
const assetAttrsConfig = {
|
|
link: ['href'],
|
|
video: ['src', 'poster'],
|
|
source: ['src'],
|
|
img: ['src'],
|
|
image: ['xlink:href', 'href'],
|
|
use: ['xlink:href', 'href']
|
|
};
|
|
// compile index.html to a JS module, importing referenced assets
|
|
// and scripts
|
|
const compileHtml = async (root, html, publicBasePath, assetsDir, inlineLimit, resolver, assets) => {
|
|
const { parse, transform } = require('@vue/compiler-dom');
|
|
// @vue/compiler-core doesn't like lowercase doctypes
|
|
html = html.replace(/<!doctype\s/i, '<!DOCTYPE ');
|
|
const ast = parse(html);
|
|
let js = '';
|
|
const s = new magic_string_1.default(html);
|
|
const assetUrls = [];
|
|
const viteHtmlTransform = (node) => {
|
|
if (node.type === 1 /* ELEMENT */) {
|
|
if (node.tag === 'script') {
|
|
let shouldRemove = false;
|
|
const srcAttr = node.props.find((p) => p.type === 6 /* ATTRIBUTE */ && p.name === 'src');
|
|
const typeAttr = node.props.find((p) => p.type === 6 /* ATTRIBUTE */ && p.name === 'type');
|
|
const isJsModule = typeAttr && typeAttr.value && typeAttr.value.content === 'module';
|
|
if (isJsModule) {
|
|
if (srcAttr && srcAttr.value) {
|
|
if (!utils_1.isExternalUrl(srcAttr.value.content)) {
|
|
// <script type="module" src="..."/>
|
|
// add it as an import
|
|
js += `\nimport ${JSON.stringify(srcAttr.value.content)}`;
|
|
shouldRemove = true;
|
|
}
|
|
}
|
|
else if (node.children.length) {
|
|
// <script type="module">...</script>
|
|
// add its content
|
|
// TODO: if there are multiple inline module scripts on the page,
|
|
// they should technically be turned into separate modules, but
|
|
// it's hard to imagine any reason for anyone to do that.
|
|
js += `\n` + node.children[0].content.trim() + `\n`;
|
|
shouldRemove = true;
|
|
}
|
|
}
|
|
if (shouldRemove) {
|
|
// remove the script tag from the html. we are going to inject new
|
|
// ones in the end.
|
|
s.remove(node.loc.start.offset, node.loc.end.offset);
|
|
}
|
|
}
|
|
// For asset references in index.html, also generate an import
|
|
// statement for each - this will be handled by the asset plugin
|
|
const assetAttrs = assetAttrsConfig[node.tag];
|
|
if (assetAttrs) {
|
|
for (const p of node.props) {
|
|
if (p.type === 6 /* ATTRIBUTE */ &&
|
|
p.value &&
|
|
assetAttrs.includes(p.name) &&
|
|
!utils_1.isExternalUrl(p.value.content) &&
|
|
!utils_1.isDataUrl(p.value.content)) {
|
|
assetUrls.push(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
transform(ast, {
|
|
nodeTransforms: [viteHtmlTransform]
|
|
});
|
|
// for each encountered asset url, rewrite original html so that it
|
|
// references the post-build location.
|
|
for (const attr of assetUrls) {
|
|
const value = attr.value;
|
|
const { fileName, content, url } = await buildPluginAsset_1.resolveAsset(resolver.requestToFile(value.content), root, publicBasePath, assetsDir, utils_1.cleanUrl(value.content).endsWith('.css') ? 0 : inlineLimit);
|
|
s.overwrite(value.loc.start.offset, value.loc.end.offset, `"${url}"`);
|
|
if (fileName && content) {
|
|
assets.set(fileName, content);
|
|
}
|
|
}
|
|
return {
|
|
html: s.toString(),
|
|
js
|
|
};
|
|
};
|
|
//# sourceMappingURL=buildPluginHtml.js.map
|