@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/README.md +57 -5
- package/dist/cli.cjs +15 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +15 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +227 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +226 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|
|
1185
|
-
const req =
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
};
|