@octohash/vite-config 0.2.2 → 0.2.3

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.mjs ADDED
@@ -0,0 +1,628 @@
1
+ import { isPackageExists } from 'local-pkg';
2
+ import { defineConfig as defineConfig$1, mergeConfig } from 'vite';
3
+ import { existsSync } from 'node:fs';
4
+ import path, { join, resolve, isAbsolute } from 'node:path';
5
+ import process from 'node:process';
6
+ import deepmerge from 'deepmerge';
7
+ import { findUp } from 'find-up';
8
+ import { readPackageJSON } from 'pkg-types';
9
+ import fsp from 'node:fs/promises';
10
+ import { visualizer } from 'rollup-plugin-visualizer';
11
+ import { fileURLToPath } from 'node:url';
12
+ import { EOL } from 'node:os';
13
+ import dayjs from 'dayjs';
14
+ import Vue from '@vitejs/plugin-vue';
15
+ import VueJsx from '@vitejs/plugin-vue-jsx';
16
+ import Dts from 'vite-plugin-dts';
17
+
18
+ function getProjectType() {
19
+ const htmlPath = join(process.cwd(), "index.html");
20
+ return existsSync(htmlPath) ? "app" : "lib";
21
+ }
22
+ async function loadMergedPackageJson() {
23
+ const root = process.cwd();
24
+ const rootPkgJsonPath = await findUp("pnpm-lock.yaml", {
25
+ cwd: root,
26
+ type: "file"
27
+ });
28
+ const rootPkgJson = rootPkgJsonPath ? await readPackageJSON(rootPkgJsonPath) : {};
29
+ const pkgJson = await readPackageJSON(root);
30
+ return deepmerge(rootPkgJson, pkgJson);
31
+ }
32
+ function extractAuthorInfo(pkgJson) {
33
+ const { author } = pkgJson;
34
+ const isObject = typeof author === "object";
35
+ const name = isObject ? author.name : author;
36
+ const email = isObject ? author.email : void 0;
37
+ const url = isObject ? author.url : void 0;
38
+ return {
39
+ name,
40
+ email,
41
+ url
42
+ };
43
+ }
44
+ async function loadConditionPlugins(conditionPlugins) {
45
+ const plugins = [];
46
+ for (const conditionPlugin of conditionPlugins) {
47
+ if (conditionPlugin.condition) {
48
+ const realPlugins = await conditionPlugin.plugins();
49
+ plugins.push(...realPlugins);
50
+ }
51
+ }
52
+ return plugins.flat();
53
+ }
54
+ function resolveSubOptions(options, key) {
55
+ return typeof options[key] === "boolean" ? {} : options[key] || {};
56
+ }
57
+
58
+ const INJECT_SCRIPT = `
59
+ <script data-app-loading="inject-js">
60
+ ;(function () {
61
+ const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
62
+ const setting = localStorage.getItem('vueuse-color-scheme') || 'auto'
63
+ if (setting === 'dark' || (prefersDark && setting !== 'light'))
64
+ document.documentElement.classList.toggle('dark', true)
65
+ })()
66
+ <\/script>
67
+ `;
68
+ async function AppLoadingPlugin(options) {
69
+ const {
70
+ rootContainer = "app",
71
+ title = "",
72
+ filePath = path.join(__dirname, "./default-loading.html")
73
+ } = options || {};
74
+ const loadingHtml = await getLoadingRawByHtmlTemplate(filePath);
75
+ return {
76
+ name: "vite-plugin-app-loading",
77
+ enforce: "pre",
78
+ transformIndexHtml: {
79
+ order: "pre",
80
+ handler: (html) => {
81
+ const rootContainerPattern = new RegExp(`<div id="${rootContainer}"\\s*></div>`, "i");
82
+ if (!rootContainerPattern.test(html)) {
83
+ return html;
84
+ }
85
+ const processedLoadingHtml = loadingHtml.replace(
86
+ "[app-loading-title]",
87
+ title
88
+ );
89
+ const injectedContent = `${INJECT_SCRIPT}${processedLoadingHtml}`;
90
+ return html.replace(
91
+ rootContainerPattern,
92
+ `<div id="${rootContainer}">${injectedContent}</div>`
93
+ );
94
+ }
95
+ }
96
+ };
97
+ }
98
+ async function getLoadingRawByHtmlTemplate(filePath) {
99
+ return await fsp.readFile(filePath, "utf8");
100
+ }
101
+
102
+ const scopeUrl = fileURLToPath(new URL(".", import.meta.url));
103
+ const isCwdInScope = isPackageExists("@octohash/vite-config");
104
+ function isPackageInScope(name) {
105
+ return isPackageExists(name, { paths: [scopeUrl] });
106
+ }
107
+ async function ensurePackages(packages) {
108
+ if (process.env.CI || process.stdout.isTTY === false || isCwdInScope === false)
109
+ return;
110
+ const nonExistingPackages = packages.filter((i) => i && !isPackageInScope(i));
111
+ if (nonExistingPackages.length === 0)
112
+ return;
113
+ const p = await import('@clack/prompts');
114
+ const result = await p.confirm({
115
+ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`
116
+ });
117
+ if (result)
118
+ await import('@antfu/install-pkg').then((i) => i.installPackage(nonExistingPackages, { dev: true }));
119
+ }
120
+
121
+ async function LicensePlugin(options) {
122
+ const licenseText = await generateLicenseText(options || {});
123
+ return {
124
+ name: "vite-plugin-license",
125
+ enforce: "post",
126
+ apply: "build",
127
+ generateBundle: {
128
+ order: "post",
129
+ handler: (_options, bundle) => {
130
+ for (const [, fileContent] of Object.entries(bundle)) {
131
+ if (fileContent.type === "chunk" && fileContent.isEntry) {
132
+ const chunkContent = fileContent;
133
+ const content = chunkContent.code;
134
+ const updatedContent = `${licenseText}${EOL}${content}`;
135
+ fileContent.code = updatedContent;
136
+ }
137
+ }
138
+ }
139
+ }
140
+ };
141
+ }
142
+ async function generateLicenseText(options) {
143
+ const pkgJson = await loadMergedPackageJson();
144
+ const { name: authorName, email: authorEmail, url: authorUrl } = extractAuthorInfo(pkgJson);
145
+ const {
146
+ name = pkgJson.name,
147
+ author = authorName,
148
+ version = pkgJson.version,
149
+ description = pkgJson.description,
150
+ homepage = pkgJson.homepage ?? authorUrl,
151
+ license,
152
+ contact = authorEmail,
153
+ copyright = {
154
+ holder: authorName,
155
+ year: (/* @__PURE__ */ new Date()).getFullYear()
156
+ }
157
+ } = options ?? {};
158
+ const date = dayjs().format("YYYY-MM-DD");
159
+ const lines = [];
160
+ lines.push("/*!");
161
+ if (name)
162
+ lines.push(` * ${name}`);
163
+ if (version)
164
+ lines.push(` * Version: ${version}`);
165
+ if (author)
166
+ lines.push(` * Author: ${author}`);
167
+ if (license)
168
+ lines.push(` * License: ${license}`);
169
+ if (description)
170
+ lines.push(` * Description: ${description}`);
171
+ if (homepage)
172
+ lines.push(` * Homepage: ${homepage}`);
173
+ if (contact)
174
+ lines.push(` * Contact: ${contact}`);
175
+ if (copyright?.holder)
176
+ lines.push(` * Copyright (C) ${copyright.year} ${copyright.holder}`);
177
+ if (date)
178
+ lines.push(` * Date: ${date}`);
179
+ lines.push(" */");
180
+ return lines.join("\n");
181
+ }
182
+
183
+ async function loadCommonPlugins(options) {
184
+ const {
185
+ isBuild,
186
+ visualizer: visualizer$1 = false,
187
+ license = true,
188
+ federation
189
+ } = options;
190
+ ensurePackages([
191
+ federation ? "@originjs/vite-plugin-federation" : void 0
192
+ ]);
193
+ return await loadConditionPlugins([
194
+ {
195
+ condition: isBuild && !!visualizer$1,
196
+ plugins: () => [
197
+ visualizer(
198
+ typeof visualizer$1 === "boolean" ? {
199
+ filename: "./node_modules/.cache/visualizer/stats.html",
200
+ gzipSize: true,
201
+ open: true
202
+ } : visualizer$1
203
+ )
204
+ ]
205
+ },
206
+ {
207
+ condition: isBuild && !!license,
208
+ plugins: async () => [
209
+ await LicensePlugin(
210
+ typeof license === "boolean" ? void 0 : license
211
+ )
212
+ ]
213
+ },
214
+ {
215
+ condition: !!federation,
216
+ plugins: async () => {
217
+ const module = await import('@originjs/vite-plugin-federation');
218
+ return [
219
+ module.default(federation)
220
+ ];
221
+ }
222
+ }
223
+ ]);
224
+ }
225
+
226
+ const shimsSubpath = `dist/es-module-shims.js`;
227
+ const providerShimsMap = {
228
+ "jspm.io": `https://ga.jspm.io/npm:es-module-shims@{version}/${shimsSubpath}`,
229
+ "jsdelivr": `https://cdn.jsdelivr.net/npm/es-module-shims@{version}/${shimsSubpath}`,
230
+ "unpkg": `https://unpkg.com/es-module-shims@{version}/${shimsSubpath}`,
231
+ "esm.sh": `https://esm.sh/es-module-shims@{version}/${shimsSubpath}`
232
+ };
233
+ async function ImportMapPlugin(options = {}) {
234
+ await ensurePackages(["vite-plugin-jspm"]);
235
+ const module = await import('vite-plugin-jspm');
236
+ const {
237
+ defaultProvider = "jspm.io",
238
+ include = [],
239
+ exclude = []
240
+ } = options;
241
+ const [scan, mapping, post] = await module.default({
242
+ ...options,
243
+ pollyfillProvider: (version) => providerShimsMap[defaultProvider]?.replace("{version}", version)
244
+ });
245
+ const _resolveId = scan.resolveId;
246
+ scan.resolveId = function(id, importer, ctx) {
247
+ if (include.length && !include.includes(id) || exclude.length && exclude.includes(id)) {
248
+ return null;
249
+ }
250
+ return typeof _resolveId === "function" ? _resolveId.call(this, id, importer, ctx) : null;
251
+ };
252
+ const _load = mapping.load;
253
+ mapping.load = function(id) {
254
+ if (include.length && !include.includes(id)) {
255
+ return null;
256
+ }
257
+ return typeof _load === "function" ? _load.call(this, id) : null;
258
+ };
259
+ return [scan, mapping, post];
260
+ }
261
+
262
+ async function MetadataPlugin(options) {
263
+ const { extendMetadata = {} } = options ?? {};
264
+ const pkgJson = await loadMergedPackageJson();
265
+ const { name, description, homepage, license, version } = pkgJson;
266
+ const { name: authorName, email: authorEmail, url: authorUrl } = extractAuthorInfo(pkgJson);
267
+ const buildTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
268
+ return {
269
+ name: "vite-plugin-metadata",
270
+ enforce: "post",
271
+ config: () => {
272
+ return {
273
+ define: {
274
+ __VITE_APP_METADATA__: JSON.stringify({
275
+ authorName,
276
+ authorEmail,
277
+ authorUrl,
278
+ buildTime,
279
+ name,
280
+ description,
281
+ homepage,
282
+ license,
283
+ version,
284
+ ...extendMetadata
285
+ })
286
+ }
287
+ };
288
+ }
289
+ };
290
+ }
291
+
292
+ async function loadVuePlugins(projectType, options) {
293
+ const { isBuild } = options;
294
+ const isApp = projectType === "app";
295
+ const {
296
+ devtools = false,
297
+ i18n = false,
298
+ imports = isApp,
299
+ components = isApp,
300
+ pages = isApp
301
+ } = resolveSubOptions(options, "vue");
302
+ await ensurePackages([
303
+ devtools ? "vite-plugin-vue-devtools" : void 0,
304
+ i18n ? "@intlify/unplugin-vue-i18n" : void 0
305
+ ]);
306
+ return loadConditionPlugins([
307
+ {
308
+ condition: true,
309
+ plugins: () => [
310
+ Vue(),
311
+ VueJsx()
312
+ ]
313
+ },
314
+ {
315
+ condition: !isBuild && !!devtools,
316
+ plugins: async () => {
317
+ const module = await import('vite-plugin-vue-devtools');
318
+ return [
319
+ module.default(
320
+ typeof devtools === "boolean" ? void 0 : devtools
321
+ )
322
+ ];
323
+ }
324
+ },
325
+ {
326
+ condition: !!i18n,
327
+ plugins: async () => {
328
+ const module = await import('@intlify/unplugin-vue-i18n/vite');
329
+ return [
330
+ module.default(
331
+ typeof i18n === "boolean" ? {
332
+ compositionOnly: true,
333
+ fullInstall: true,
334
+ runtimeOnly: true
335
+ } : i18n
336
+ )
337
+ ];
338
+ }
339
+ },
340
+ {
341
+ condition: isApp && !!imports,
342
+ plugins: async () => {
343
+ const module = await import('unplugin-auto-import/vite');
344
+ return [
345
+ module.default(
346
+ typeof imports === "boolean" ? {
347
+ dts: "src/typings/auto-imports.d.ts",
348
+ imports: await resolveAutoImports(),
349
+ resolvers: await resolveUIComponentResolvers(),
350
+ dirs: [
351
+ "src/composables",
352
+ "src/utils"
353
+ ],
354
+ vueTemplate: true
355
+ } : imports
356
+ )
357
+ ];
358
+ }
359
+ },
360
+ {
361
+ condition: isApp && !!components,
362
+ plugins: async () => {
363
+ const module = await import('unplugin-vue-components/vite');
364
+ return [
365
+ module.default(
366
+ typeof components === "boolean" ? {
367
+ dts: "src/typings/components.d.ts",
368
+ directoryAsNamespace: true
369
+ } : components
370
+ )
371
+ ];
372
+ }
373
+ },
374
+ {
375
+ condition: isApp && !!pages,
376
+ plugins: async () => {
377
+ const module = await import('unplugin-vue-router/vite');
378
+ return [
379
+ module.default(
380
+ typeof pages === "boolean" ? {
381
+ dts: "src/typings/typed-router.d.ts"
382
+ } : pages
383
+ )
384
+ ];
385
+ }
386
+ }
387
+ ]);
388
+ }
389
+ async function resolveAutoImports() {
390
+ const imports = ["vue"];
391
+ if (isPackageExists("vue-router"))
392
+ imports.push("vue-router");
393
+ if (isPackageExists("pinia"))
394
+ imports.push("pinia");
395
+ if (isPackageExists("@vueuse/core"))
396
+ imports.push("@vueuse/core");
397
+ if (isPackageExists("vue-i18n"))
398
+ imports.push("vue-i18n");
399
+ return imports;
400
+ }
401
+ async function resolveUIComponentResolvers() {
402
+ const resolvers = [];
403
+ if (isPackageExists("ant-design-vue")) {
404
+ const { AntDesignVueResolver } = await import('unplugin-vue-components/resolvers');
405
+ resolvers.push(
406
+ AntDesignVueResolver({
407
+ importStyle: "css-in-js",
408
+ prefix: ""
409
+ })
410
+ );
411
+ }
412
+ if (isPackageExists("element-plus")) {
413
+ const { ElementPlusResolver } = await import('unplugin-vue-components/resolvers');
414
+ resolvers.push(...ElementPlusResolver());
415
+ }
416
+ if (isPackageExists("naive-ui")) {
417
+ const { NaiveUiResolver } = await import('unplugin-vue-components/resolvers');
418
+ resolvers.push(NaiveUiResolver());
419
+ }
420
+ if (isPackageExists("vant")) {
421
+ const { VantResolver } = await import('unplugin-vue-components/resolvers');
422
+ resolvers.push(VantResolver());
423
+ }
424
+ return resolvers;
425
+ }
426
+
427
+ async function loadAppPlugins(options) {
428
+ const {
429
+ isBuild,
430
+ dynamicBase,
431
+ appLoading = true,
432
+ metadata = true,
433
+ importMap = false,
434
+ vue
435
+ } = options;
436
+ const plugins = await loadCommonPlugins(options);
437
+ plugins.push(await loadConditionPlugins([
438
+ {
439
+ condition: !!dynamicBase,
440
+ plugins: async () => {
441
+ const module = await import('vite-plugin-dynamic-base');
442
+ return [
443
+ module.dynamicBase({
444
+ publicPath: dynamicBase,
445
+ transformIndexHtml: true
446
+ })
447
+ ];
448
+ }
449
+ },
450
+ {
451
+ condition: !!appLoading,
452
+ plugins: async () => [
453
+ await AppLoadingPlugin(
454
+ typeof appLoading === "boolean" ? void 0 : appLoading
455
+ )
456
+ ]
457
+ },
458
+ {
459
+ condition: !!metadata,
460
+ plugins: async () => {
461
+ return [
462
+ await MetadataPlugin(
463
+ typeof metadata === "boolean" ? void 0 : metadata
464
+ )
465
+ ];
466
+ }
467
+ },
468
+ {
469
+ condition: isBuild && !!importMap,
470
+ plugins: () => {
471
+ return [
472
+ ImportMapPlugin(
473
+ typeof importMap === "boolean" ? void 0 : importMap
474
+ )
475
+ ];
476
+ }
477
+ }
478
+ ]));
479
+ if (vue)
480
+ plugins.push(await loadVuePlugins("app", options));
481
+ return plugins;
482
+ }
483
+
484
+ async function getCommonConfig(options) {
485
+ const { alias = {} } = options;
486
+ const resolvedAlias = Object.entries(alias).reduce((acc, [key, value]) => {
487
+ acc[key] = isAbsolute(value) ? value : resolve(process.cwd(), value);
488
+ return acc;
489
+ }, {});
490
+ return {
491
+ resolve: {
492
+ alias: {
493
+ "@": resolve(process.cwd(), "./src"),
494
+ ...resolvedAlias
495
+ }
496
+ },
497
+ build: {
498
+ chunkSizeWarningLimit: 2e3,
499
+ reportCompressedSize: false,
500
+ sourcemap: false
501
+ }
502
+ };
503
+ }
504
+
505
+ function defineAppConfig(options) {
506
+ return defineConfig$1(async (config) => {
507
+ const { dynamicBase, vite = {} } = options;
508
+ const { command } = config;
509
+ const isBuild = command === "build";
510
+ const plugins = await loadAppPlugins({
511
+ ...options,
512
+ isBuild
513
+ });
514
+ const appConfig = {
515
+ base: dynamicBase ? "/__dynamic_base__/" : "/",
516
+ plugins,
517
+ build: {
518
+ target: "es2015",
519
+ rollupOptions: {
520
+ output: {
521
+ assetFileNames: "[ext]/[name]-[hash].[ext]",
522
+ chunkFileNames: "js/[name]-[hash].js",
523
+ entryFileNames: "jse/index-[name]-[hash].js"
524
+ }
525
+ }
526
+ },
527
+ esbuild: {
528
+ drop: isBuild ? [
529
+ // 'console',
530
+ "debugger"
531
+ ] : [],
532
+ legalComments: "none"
533
+ },
534
+ server: {
535
+ host: true
536
+ }
537
+ };
538
+ const mergedCommonConfig = mergeConfig(
539
+ await getCommonConfig(options),
540
+ appConfig
541
+ );
542
+ return mergeConfig(mergedCommonConfig, vite);
543
+ });
544
+ }
545
+
546
+ async function loadLibPlugins(options) {
547
+ const {
548
+ isBuild,
549
+ dts = true,
550
+ vue
551
+ } = options;
552
+ const plugins = await loadCommonPlugins(options);
553
+ plugins.push(await loadConditionPlugins([
554
+ {
555
+ condition: isBuild && !!dts,
556
+ plugins: () => [
557
+ Dts(
558
+ typeof dts === "boolean" ? {
559
+ logLevel: "error"
560
+ } : dts
561
+ )
562
+ ]
563
+ }
564
+ ]));
565
+ if (vue)
566
+ plugins.push(await loadVuePlugins("lib", options));
567
+ return plugins;
568
+ }
569
+
570
+ function defineLibConfig(options) {
571
+ return defineConfig$1(async (config) => {
572
+ const root = process.cwd();
573
+ const { vite = {} } = options;
574
+ const { command } = config;
575
+ const isBuild = command === "build";
576
+ const plugins = await loadLibPlugins({
577
+ ...options,
578
+ isBuild
579
+ });
580
+ const { dependencies = {}, peerDependencies = {} } = await readPackageJSON(root);
581
+ const externalPackages = [
582
+ ...Object.keys(dependencies),
583
+ ...Object.keys(peerDependencies)
584
+ ];
585
+ const libConfig = {
586
+ plugins,
587
+ build: {
588
+ lib: {
589
+ entry: "src/index.ts",
590
+ fileName: () => "index.mjs",
591
+ formats: ["es"]
592
+ },
593
+ rollupOptions: {
594
+ external: (id) => {
595
+ return externalPackages.some(
596
+ (pkg) => id === pkg || id.startsWith(`${pkg}/`)
597
+ );
598
+ }
599
+ }
600
+ }
601
+ };
602
+ const mergedCommonConfig = mergeConfig(
603
+ await getCommonConfig(options),
604
+ libConfig
605
+ );
606
+ return mergeConfig(mergedCommonConfig, vite);
607
+ });
608
+ }
609
+
610
+ const VUE_PACKAGES = ["vue", "nuxt", "vitepress"];
611
+
612
+ function defineConfig(options) {
613
+ const resolved = {
614
+ type: getProjectType(),
615
+ vue: VUE_PACKAGES.some((pkg) => isPackageExists(pkg)),
616
+ ...options
617
+ };
618
+ switch (resolved.type) {
619
+ case "app":
620
+ return defineAppConfig(resolved);
621
+ case "lib":
622
+ return defineLibConfig(resolved);
623
+ default:
624
+ throw new Error(`Unsupported project type: ${resolved.type}`);
625
+ }
626
+ }
627
+
628
+ export { defineConfig };