vite-plugin-multi-page-css
Version:
143 lines (140 loc) • 3.94 kB
JavaScript
import path from 'path';
import fs from 'fs';
import url from 'url';
import fg from 'fast-glob';
import ejs from 'ejs';
function flattenSet(inputSet) {
const flatSet = /* @__PURE__ */ new Set();
function recursiveFlatten(set) {
set.forEach((item) => {
if (item instanceof Set) {
recursiveFlatten(item);
} else {
flatSet.add(item);
}
});
}
recursiveFlatten(inputSet);
return flatSet;
}
function genImportCss(item, container) {
const result = /* @__PURE__ */ new Set();
function processImports(imports) {
for (const element of imports) {
const i = container[element];
if (i.viteMetadata?.importedCss) {
result.add(i.viteMetadata.importedCss);
}
if (i.imports?.length > 0) {
processImports(i.imports);
}
}
}
if (item.imports?.length > 0) {
processImports(item.imports);
}
return result;
}
function multiPagePlugin(options = {}) {
const {
splitCss = false,
template = "index.html",
pageDir = path.join("src", "pages")
//TODO 后续有时间再搞吧
//pages=[],
} = options;
const dirNames = fg.sync("*/", { cwd: pageDir, onlyDirectories: true });
const htmlNames = dirNames.map((dirName) => `${dirName}.html`);
const templatePath = path.join(pageDir, template);
const indexHtml = fs.readFileSync(templatePath, "utf8");
const templateUrl = templatePath.split(path.sep).join("/");
let viteConfig = null;
return {
name: "vite:multi-page",
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
},
config() {
const input = Object.fromEntries(
dirNames.map((dirName) => [dirName, `${dirName}.html`])
);
return {
build: {
rollupOptions: {
input
}
}
};
},
resolveId(id) {
if (htmlNames.indexOf(id) > -1) {
return id;
}
},
load(id) {
if (htmlNames.indexOf(id) > -1) {
return indexHtml;
}
},
configureServer(server) {
server.middlewares.use((req, res, next) => {
const reqUrl = req.url;
const baseName = url.parse(reqUrl).pathname;
if (baseName?.endsWith(".html")) {
req.url = `/${templateUrl}`;
}
next();
});
},
transformIndexHtml: {
enforce: "pre",
async transform(html, ctx) {
const name = ctx.originalUrl || ctx.filename;
if (!name)
return html;
const pathname = url.parse(name).pathname;
if (!pathname)
return html;
const pageName = path.basename(pathname, ".html");
const renderedHtml = ejs.render(html, { ctx: viteConfig });
const _html = renderedHtml.replace(
/<\/body>/,
`<script type="module" src="./${pageDir}/${pageName}/index.tsx"><\/script>
</body>`
);
return {
html: _html,
tags: []
};
}
},
generateBundle(_options, bundle) {
if (!splitCss) {
return;
}
for (const fileName in bundle) {
const fileInfo = bundle[fileName];
if (fileName.endsWith(".js") && fileName.indexOf("/") == -1) {
const cssAssets = genImportCss(fileInfo, bundle);
cssAssets.add(fileInfo.viteMetadata?.importedCss);
let cssSource = "";
const importCssSet = flattenSet(cssAssets);
if (importCssSet.size > 0) {
for (const item of importCssSet) {
cssSource += `/** ${item} */
${bundle[item].source}`;
}
const fileWithoutExtension = path.parse(fileName).name;
const cssFileName = `${fileWithoutExtension}.css`;
bundle[cssFileName] = {
type: "asset",
source: cssSource,
fileName: cssFileName
};
}
}
}
}
};
}
export { multiPagePlugin as default };