@nasti-toolchain/nasti 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -295,4 +295,25 @@ declare function startElectronDev(inlineConfig?: ElectronDevOptions): Promise<vo
295
295
  */
296
296
  declare function electronPlugin(config: ResolvedConfig): NastiPlugin;
297
297
 
298
- export { type DevServer, type ElectronConfig, type HmrPayload, type ModuleNode, type NastiConfig, type NastiPlugin, type ResolvedConfig, type TransformResult, build, buildElectron, createServer, defineConfig, electronPlugin, resolveConfig, startElectronDev };
298
+ type MonacoEditorLanguageWorker = 'editorWorkerService' | 'css' | 'html' | 'json' | 'typescript';
299
+ interface MonacoCustomWorker {
300
+ label: string;
301
+ entry: string;
302
+ }
303
+ interface MonacoEditorPluginOptions {
304
+ /** 启用的 Monaco 语言 Worker,默认启用全部 */
305
+ languageWorkers?: MonacoEditorLanguageWorker[];
306
+ /** 额外自定义 Worker(如 monaco-graphql/esm/graphql.worker) */
307
+ customWorkers?: MonacoCustomWorker[];
308
+ /** Worker 在 URL 上的公共路径,默认 'monacoeditorwork'。可填 CDN 绝对 URL */
309
+ publicPath?: string;
310
+ /** 是否将 Monaco API 暴露到 window.monaco(兼容 0.22 之前的 globalAPI 模式) */
311
+ globalAPI?: boolean;
312
+ /** publicPath 是 CDN 时仍强制本地打包 Worker 产物 */
313
+ forceBuildCDN?: boolean;
314
+ /** 自定义生产构建下 Worker 产物目录(绝对路径) */
315
+ customDistPath?: (root: string, outDir: string, base: string) => string;
316
+ }
317
+ declare function monacoEditorPlugin(options?: MonacoEditorPluginOptions): NastiPlugin;
318
+
319
+ export { type DevServer, type ElectronConfig, type HmrPayload, type ModuleNode, type MonacoCustomWorker, type MonacoEditorLanguageWorker, type MonacoEditorPluginOptions, type NastiConfig, type NastiPlugin, type ResolvedConfig, type TransformResult, build, buildElectron, createServer, defineConfig, electronPlugin, monacoEditorPlugin, resolveConfig, startElectronDev };
package/dist/index.d.ts CHANGED
@@ -295,4 +295,25 @@ declare function startElectronDev(inlineConfig?: ElectronDevOptions): Promise<vo
295
295
  */
296
296
  declare function electronPlugin(config: ResolvedConfig): NastiPlugin;
297
297
 
298
- export { type DevServer, type ElectronConfig, type HmrPayload, type ModuleNode, type NastiConfig, type NastiPlugin, type ResolvedConfig, type TransformResult, build, buildElectron, createServer, defineConfig, electronPlugin, resolveConfig, startElectronDev };
298
+ type MonacoEditorLanguageWorker = 'editorWorkerService' | 'css' | 'html' | 'json' | 'typescript';
299
+ interface MonacoCustomWorker {
300
+ label: string;
301
+ entry: string;
302
+ }
303
+ interface MonacoEditorPluginOptions {
304
+ /** 启用的 Monaco 语言 Worker,默认启用全部 */
305
+ languageWorkers?: MonacoEditorLanguageWorker[];
306
+ /** 额外自定义 Worker(如 monaco-graphql/esm/graphql.worker) */
307
+ customWorkers?: MonacoCustomWorker[];
308
+ /** Worker 在 URL 上的公共路径,默认 'monacoeditorwork'。可填 CDN 绝对 URL */
309
+ publicPath?: string;
310
+ /** 是否将 Monaco API 暴露到 window.monaco(兼容 0.22 之前的 globalAPI 模式) */
311
+ globalAPI?: boolean;
312
+ /** publicPath 是 CDN 时仍强制本地打包 Worker 产物 */
313
+ forceBuildCDN?: boolean;
314
+ /** 自定义生产构建下 Worker 产物目录(绝对路径) */
315
+ customDistPath?: (root: string, outDir: string, base: string) => string;
316
+ }
317
+ declare function monacoEditorPlugin(options?: MonacoEditorPluginOptions): NastiPlugin;
318
+
319
+ export { type DevServer, type ElectronConfig, type HmrPayload, type ModuleNode, type MonacoCustomWorker, type MonacoEditorLanguageWorker, type MonacoEditorPluginOptions, type NastiConfig, type NastiPlugin, type ResolvedConfig, type TransformResult, build, buildElectron, createServer, defineConfig, electronPlugin, monacoEditorPlugin, resolveConfig, startElectronDev };
package/dist/index.js CHANGED
@@ -701,7 +701,7 @@ import pc from "picocolors";
701
701
  async function build(inlineConfig = {}) {
702
702
  const config = await resolveConfig(inlineConfig, "build");
703
703
  const startTime = performance.now();
704
- console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${"1.4.0"}`));
704
+ console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${"1.5.0"}`));
705
705
  console.log(pc.dim(` root: ${config.root}`));
706
706
  console.log(pc.dim(` mode: ${config.mode}`));
707
707
  const outDir = path7.resolve(config.root, config.build.outDir);
@@ -1181,8 +1181,8 @@ function rewriteExternalRequires(code) {
1181
1181
  }
1182
1182
  async function injectCjsNamedExports(code, entryFile) {
1183
1183
  try {
1184
- const { createRequire: createRequire3 } = await import("module");
1185
- const req = createRequire3(entryFile);
1184
+ const { createRequire: createRequire4 } = await import("module");
1185
+ const req = createRequire4(entryFile);
1186
1186
  const cjsExports = req(entryFile);
1187
1187
  if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
1188
1188
  const namedKeys = Object.keys(cjsExports).filter(
@@ -1577,15 +1577,6 @@ async function createServer(inlineConfig = {}) {
1577
1577
  watcher.on("add", (file) => {
1578
1578
  handleFileChange(file, server);
1579
1579
  });
1580
- const postMiddlewares = [];
1581
- for (const plugin of allPlugins) {
1582
- if (plugin.configureServer) {
1583
- const result = await plugin.configureServer(server);
1584
- if (typeof result === "function") {
1585
- postMiddlewares.push(result);
1586
- }
1587
- }
1588
- }
1589
1580
  server = {
1590
1581
  config: configWithPlugins,
1591
1582
  middlewares: app,
@@ -1604,7 +1595,7 @@ async function createServer(inlineConfig = {}) {
1604
1595
  const localUrl = `http://localhost:${actualPort}`;
1605
1596
  const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
1606
1597
  console.log();
1607
- console.log(pc3.cyan(" nasti dev server") + pc3.dim(` v${"1.4.0"}`));
1598
+ console.log(pc3.cyan(" nasti dev server") + pc3.dim(` v${"1.5.0"}`));
1608
1599
  console.log();
1609
1600
  console.log(` ${pc3.green(">")} Local: ${pc3.cyan(localUrl)}`);
1610
1601
  if (networkUrl) {
@@ -1637,6 +1628,16 @@ async function createServer(inlineConfig = {}) {
1637
1628
  httpServer.close();
1638
1629
  }
1639
1630
  };
1631
+ const postMiddlewares = [];
1632
+ for (const plugin of allPlugins) {
1633
+ if (plugin.configureServer) {
1634
+ const result = await plugin.configureServer(server);
1635
+ if (typeof result === "function") {
1636
+ postMiddlewares.push(result);
1637
+ }
1638
+ }
1639
+ }
1640
+ for (const run of postMiddlewares) run();
1640
1641
  return server;
1641
1642
  }
1642
1643
  function getNetworkAddress() {
@@ -1718,7 +1719,7 @@ async function buildElectron(inlineConfig = {}) {
1718
1719
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
1719
1720
  const startTime = performance.now();
1720
1721
  assertElectronVersion(config);
1721
- console.log(pc2.cyan("\n\u26A1 nasti build (electron)") + pc2.dim(` v${"1.4.0"}`));
1722
+ console.log(pc2.cyan("\n\u26A1 nasti build (electron)") + pc2.dim(` v${"1.5.0"}`));
1722
1723
  console.log(pc2.dim(` root: ${config.root}`));
1723
1724
  console.log(pc2.dim(` mode: ${config.mode}`));
1724
1725
  console.log(pc2.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -1865,7 +1866,7 @@ async function startElectronDev(inlineConfig = {}) {
1865
1866
  const { noSpawn, ...rest } = inlineConfig;
1866
1867
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
1867
1868
  warnElectronVersion(config);
1868
- console.log(pc4.cyan("\n\u26A1 nasti electron dev") + pc4.dim(` v${"1.4.0"}`));
1869
+ console.log(pc4.cyan("\n\u26A1 nasti electron dev") + pc4.dim(` v${"1.5.0"}`));
1869
1870
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
1870
1871
  const server = await createServer2({ ...rest, target: "electron" });
1871
1872
  await server.listen();
@@ -2028,12 +2029,222 @@ function warnElectronVersion(config) {
2028
2029
  );
2029
2030
  }
2030
2031
  }
2032
+
2033
+ // src/plugins/monaco-editor.ts
2034
+ import path13 from "path";
2035
+ import fs11 from "fs";
2036
+ import crypto2 from "crypto";
2037
+ import { createRequire as createRequire3 } from "module";
2038
+ var DEFAULT_WORKERS = {
2039
+ editorWorkerService: "monaco-editor/esm/vs/editor/editor.worker",
2040
+ css: "monaco-editor/esm/vs/language/css/css.worker",
2041
+ html: "monaco-editor/esm/vs/language/html/html.worker",
2042
+ json: "monaco-editor/esm/vs/language/json/json.worker",
2043
+ typescript: "monaco-editor/esm/vs/language/typescript/ts.worker"
2044
+ };
2045
+ var DEFAULT_PUBLIC_PATH = "monacoeditorwork";
2046
+ function isCDN(p) {
2047
+ return /^((https?:)?\/\/|file:)/.test(p);
2048
+ }
2049
+ function normalizePublicPath(p) {
2050
+ if (isCDN(p)) return p.replace(/\/+$/, "");
2051
+ const withLead = p.startsWith("/") ? p : "/" + p;
2052
+ return withLead.replace(/\/+$/, "") || "/";
2053
+ }
2054
+ function readMonacoVersion(root) {
2055
+ try {
2056
+ const require2 = createRequire3(path13.resolve(root, "package.json"));
2057
+ const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
2058
+ const pkg = JSON.parse(fs11.readFileSync(pkgJsonPath, "utf-8"));
2059
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
2060
+ } catch {
2061
+ return "unknown";
2062
+ }
2063
+ }
2064
+ function monacoEditorPlugin(options = {}) {
2065
+ const languageWorkers = options.languageWorkers ?? Object.keys(DEFAULT_WORKERS);
2066
+ const customWorkers = options.customWorkers ?? [];
2067
+ const publicPath = normalizePublicPath(options.publicPath ?? DEFAULT_PUBLIC_PATH);
2068
+ const globalAPI = !!options.globalAPI;
2069
+ const forceBuildCDN = !!options.forceBuildCDN;
2070
+ const workers = [
2071
+ ...languageWorkers.map((label) => ({ label, entry: DEFAULT_WORKERS[label] })),
2072
+ ...customWorkers
2073
+ ];
2074
+ let resolvedConfig;
2075
+ let cacheDir = "";
2076
+ const building = /* @__PURE__ */ new Map();
2077
+ async function buildWorker(worker) {
2078
+ const cacheFile = path13.join(cacheDir, `${worker.label}.worker.js`);
2079
+ if (fs11.existsSync(cacheFile)) return cacheFile;
2080
+ const existing = building.get(worker.label);
2081
+ if (existing) return existing;
2082
+ const task = (async () => {
2083
+ const { rolldown: rolldown4 } = await import("rolldown");
2084
+ const require2 = createRequire3(path13.resolve(resolvedConfig.root, "package.json"));
2085
+ let entry;
2086
+ try {
2087
+ entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
2088
+ } catch {
2089
+ entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
2090
+ }
2091
+ fs11.mkdirSync(cacheDir, { recursive: true });
2092
+ const bundle = await rolldown4({
2093
+ input: entry,
2094
+ platform: "browser"
2095
+ });
2096
+ await bundle.write({
2097
+ file: cacheFile,
2098
+ format: "iife",
2099
+ sourcemap: false,
2100
+ minify: true,
2101
+ inlineDynamicImports: true
2102
+ });
2103
+ await bundle.close();
2104
+ return cacheFile;
2105
+ })();
2106
+ building.set(worker.label, task);
2107
+ try {
2108
+ return await task;
2109
+ } finally {
2110
+ building.delete(worker.label);
2111
+ }
2112
+ }
2113
+ function runtimeInitScript() {
2114
+ let normalizedPrefix = publicPath;
2115
+ if (!isCDN(publicPath)) {
2116
+ const base = resolvedConfig.base.replace(/\/+$/, "") || "";
2117
+ const pub = publicPath.replace(/^\/+/, "");
2118
+ normalizedPrefix = base ? `${base}/${pub}` : `/${pub}`;
2119
+ }
2120
+ const map = {};
2121
+ for (const w of workers) {
2122
+ map[w.label] = `${normalizedPrefix}/${w.label}.worker.js`;
2123
+ }
2124
+ return `;(function () {
2125
+ var map = ${JSON.stringify(map)};
2126
+ function getWorkerUrl(_moduleId, label) {
2127
+ var url = map[label] || map['editorWorkerService'];
2128
+ if (/^(https?:)?\\/\\//.test(url)) {
2129
+ // \u8DE8\u57DF Worker \u9700\u7528 Blob + importScripts \u7ED5\u8FC7\u540C\u6E90\u9650\u5236
2130
+ var blob = new Blob(
2131
+ ['importScripts(' + JSON.stringify(url) + ');'],
2132
+ { type: 'application/javascript' }
2133
+ );
2134
+ return URL.createObjectURL(blob);
2135
+ }
2136
+ return url;
2137
+ }
2138
+ self.MonacoEnvironment = self.MonacoEnvironment || {};
2139
+ if (!self.MonacoEnvironment.getWorker && !self.MonacoEnvironment.getWorkerUrl) {
2140
+ self.MonacoEnvironment.getWorkerUrl = getWorkerUrl;
2141
+ }
2142
+ })();`;
2143
+ }
2144
+ return {
2145
+ name: "nasti:monaco-editor",
2146
+ enforce: "pre",
2147
+ configResolved(config) {
2148
+ resolvedConfig = config;
2149
+ const version = readMonacoVersion(config.root);
2150
+ const key = crypto2.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
2151
+ cacheDir = path13.resolve(config.root, "node_modules/.nasti/monaco", key);
2152
+ },
2153
+ async configureServer(server) {
2154
+ const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
2155
+ const watcher = server.watcher;
2156
+ const monacoDir = path13.resolve(resolvedConfig.root, "node_modules/monaco-editor");
2157
+ try {
2158
+ watcher?.unwatch?.(monacoDir);
2159
+ } catch {
2160
+ }
2161
+ if (!shouldBuild) return;
2162
+ void Promise.all(
2163
+ workers.map(
2164
+ (w) => buildWorker(w).catch((e) => {
2165
+ console.warn(
2166
+ `[nasti:monaco-editor] worker build failed for "${w.label}": ${e.message}`
2167
+ );
2168
+ })
2169
+ )
2170
+ );
2171
+ const base = resolvedConfig.base.replace(/\/+$/, "") || "";
2172
+ const pub = publicPath.replace(/^\/+/, "");
2173
+ const prefix = (base ? `${base}/${pub}` : `/${pub}`) + "/";
2174
+ server.middlewares.use(
2175
+ async (req, res, next) => {
2176
+ if (req.method !== "GET") return next();
2177
+ const url = (req.url ?? "").split("?")[0];
2178
+ if (!url.startsWith(prefix)) return next();
2179
+ const name = url.slice(prefix.length).replace(/\.worker\.js$/, "");
2180
+ const worker = workers.find((w) => w.label === name);
2181
+ if (!worker) return next();
2182
+ try {
2183
+ const file = await buildWorker(worker);
2184
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
2185
+ res.setHeader("Cache-Control", "public, max-age=604800, immutable");
2186
+ fs11.createReadStream(file).pipe(res);
2187
+ } catch (e) {
2188
+ res.statusCode = 500;
2189
+ res.end(`Monaco worker build failed: ${e.message}`);
2190
+ }
2191
+ }
2192
+ );
2193
+ },
2194
+ transformIndexHtml(html) {
2195
+ const tags = [
2196
+ {
2197
+ tag: "script",
2198
+ children: runtimeInitScript(),
2199
+ injectTo: "head-prepend"
2200
+ }
2201
+ ];
2202
+ if (globalAPI) {
2203
+ tags.push({
2204
+ tag: "script",
2205
+ attrs: { type: "module" },
2206
+ children: `import * as monaco from 'monaco-editor';
2207
+ self.monaco = monaco;`,
2208
+ injectTo: "head"
2209
+ });
2210
+ }
2211
+ return { html, tags };
2212
+ },
2213
+ // 生产构建:把所有 Worker 预打包并拷到 outDir/<publicPath>/ 下
2214
+ async buildStart() {
2215
+ if (resolvedConfig.command !== "build") return;
2216
+ if (isCDN(publicPath) && !forceBuildCDN) return;
2217
+ const outDir = options.customDistPath ? options.customDistPath(
2218
+ resolvedConfig.root,
2219
+ resolvedConfig.build.outDir,
2220
+ resolvedConfig.base
2221
+ ) : isCDN(publicPath) ? path13.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path13.resolve(
2222
+ resolvedConfig.root,
2223
+ resolvedConfig.build.outDir,
2224
+ publicPath.replace(/^\//, "")
2225
+ );
2226
+ fs11.mkdirSync(outDir, { recursive: true });
2227
+ for (const worker of workers) {
2228
+ try {
2229
+ const cacheFile = await buildWorker(worker);
2230
+ fs11.copyFileSync(cacheFile, path13.join(outDir, `${worker.label}.worker.js`));
2231
+ } catch (e) {
2232
+ throw new Error(
2233
+ `[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
2234
+ ${e.stack || ""}`
2235
+ );
2236
+ }
2237
+ }
2238
+ }
2239
+ };
2240
+ }
2031
2241
  export {
2032
2242
  build,
2033
2243
  buildElectron,
2034
2244
  createServer,
2035
2245
  defineConfig,
2036
2246
  electronPlugin,
2247
+ monacoEditorPlugin,
2037
2248
  resolveConfig,
2038
2249
  startElectronDev
2039
2250
  };