Files
wwjcloud-nest-v1/admin-vben/internal/vite-config/src/plugins/importmap.ts
wanwu e7a1d6b4d6 🧹 清理重复配置文件
- 删除根目录中重复的 NestJS 配置文件
- 删除 tsconfig.json, tsconfig.build.json, eslint.config.mjs, .prettierrc
- 保留 wwjcloud-nest/ 目录中的完整配置
- 避免配置冲突,确保项目结构清晰
2025-10-14 23:56:20 +08:00

246 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 参考 https://github.com/jspm/vite-plugin-jspm调整为需要的功能
*/
import type { GeneratorOptions } from '@jspm/generator';
import type { Plugin } from 'vite';
import { Generator } from '@jspm/generator';
import { load } from 'cheerio';
import { minify } from 'html-minifier-terser';
const DEFAULT_PROVIDER = 'jspm.io';
type pluginOptions = GeneratorOptions & {
debug?: boolean;
defaultProvider?: 'esm.sh' | 'jsdelivr' | 'jspm.io';
importmap?: Array<{ name: string; range?: string }>;
};
// async function getLatestVersionOfShims() {
// const result = await fetch('https://ga.jspm.io/npm:es-module-shims');
// const version = result.text();
// return version;
// }
async function getShimsUrl(provide: string) {
// const version = await getLatestVersionOfShims();
const version = '1.10.0';
const shimsSubpath = `dist/es-module-shims.js`;
const providerShimsMap: Record<string, string> = {
'esm.sh': `https://esm.sh/es-module-shims@${version}/${shimsSubpath}`,
// unpkg: `https://unpkg.com/es-module-shims@${version}/${shimsSubpath}`,
jsdelivr: `https://cdn.jsdelivr.net/npm/es-module-shims@${version}/${shimsSubpath}`,
// 下面两个CDN不稳定暂时不用
'jspm.io': `https://ga.jspm.io/npm:es-module-shims@${version}/${shimsSubpath}`,
};
return providerShimsMap[provide] || providerShimsMap[DEFAULT_PROVIDER];
}
let generator: Generator;
async function viteImportMapPlugin(
pluginOptions?: pluginOptions,
): Promise<Plugin[]> {
const { importmap } = pluginOptions || {};
let isSSR = false;
let isBuild = false;
let installed = false;
let installError: Error | null = null;
const options: pluginOptions = Object.assign(
{},
{
debug: false,
defaultProvider: 'jspm.io',
env: ['production', 'browser', 'module'],
importmap: [],
},
pluginOptions,
);
generator = new Generator({
...options,
baseUrl: process.cwd(),
});
if (options?.debug) {
(async () => {
for await (const { message, type } of generator.logStream()) {
console.log(`${type}: ${message}`);
}
})();
}
const imports = options.inputMap?.imports ?? {};
const scopes = options.inputMap?.scopes ?? {};
const firstLayerKeys = Object.keys(scopes);
const inputMapScopes: string[] = [];
firstLayerKeys.forEach((key) => {
inputMapScopes.push(...Object.keys(scopes[key] || {}));
});
const inputMapImports = Object.keys(imports);
const allDepNames: string[] = [
...(importmap?.map((item) => item.name) || []),
...inputMapImports,
...inputMapScopes,
];
const depNames = new Set<string>(allDepNames);
const installDeps = importmap?.map((item) => ({
range: item.range,
target: item.name,
}));
return [
{
async config(_, { command, isSsrBuild }) {
isBuild = command === 'build';
isSSR = !!isSsrBuild;
},
enforce: 'pre',
name: 'importmap:external',
resolveId(id) {
if (isSSR || !isBuild) {
return null;
}
if (!depNames.has(id)) {
return null;
}
return { external: true, id };
},
},
{
enforce: 'post',
name: 'importmap:install',
async resolveId() {
if (isSSR || !isBuild || installed) {
return null;
}
try {
installed = true;
await Promise.allSettled(
(installDeps || []).map((dep) => generator.install(dep)),
);
} catch (error: any) {
installError = error;
installed = false;
}
return null;
},
},
{
buildEnd() {
// 未生成importmap时抛出错误防止被turbo缓存
if (!installed && !isSSR) {
installError && console.error(installError);
throw new Error('Importmap installation failed.');
}
},
enforce: 'post',
name: 'importmap:html',
transformIndexHtml: {
async handler(html) {
if (isSSR || !isBuild) {
return html;
}
const importmapJson = generator.getMap();
if (!importmapJson) {
return html;
}
const esModuleShimsSrc = await getShimsUrl(
options.defaultProvider || DEFAULT_PROVIDER,
);
const resultHtml = await injectShimsToHtml(
html,
esModuleShimsSrc || '',
);
html = await minify(resultHtml || html, {
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
removeComments: false,
});
return {
html,
tags: [
{
attrs: {
type: 'importmap',
},
injectTo: 'head-prepend',
tag: 'script',
children: `${JSON.stringify(importmapJson)}`,
},
],
};
},
order: 'post',
},
},
];
}
async function injectShimsToHtml(html: string, esModuleShimUrl: string) {
const $ = load(html);
const $script = $(`script[type='module']`);
if (!$script) {
return;
}
const entry = $script.attr('src');
$script.removeAttr('type');
$script.removeAttr('crossorigin');
$script.removeAttr('src');
$script.html(`
if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) {
self.importShim = function () {
const promise = new Promise((resolve, reject) => {
document.head.appendChild(
Object.assign(document.createElement('script'), {
src: '${esModuleShimUrl}',
crossorigin: 'anonymous',
async: true,
onload() {
if (!importShim.$proxy) {
resolve(importShim);
} else {
reject(new Error('No globalThis.importShim found:' + esModuleShimUrl));
}
},
onerror(error) {
reject(error);
},
}),
);
});
importShim.$proxy = true;
return promise.then((importShim) => importShim(...arguments));
};
}
var modules = ['${entry}'];
typeof importShim === 'function'
? modules.forEach((moduleName) => importShim(moduleName))
: modules.forEach((moduleName) => import(moduleName));
`);
$('body').after($script);
$('head').remove(`script[type='module']`);
return $.html();
}
export { viteImportMapPlugin };