jiek 2.2.1 → 2.2.3-alpha.1
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/cli-only-build.cjs +250 -145
- package/dist/cli-only-build.d.cts +11 -0
- package/dist/cli-only-build.d.ts +11 -0
- package/dist/cli-only-build.js +260 -155
- package/dist/cli.cjs +24 -20
- package/dist/cli.js +24 -20
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/rollup/index.cjs +80 -41
- package/dist/rollup/index.js +80 -41
- package/package.json +10 -6
- package/src/commands/build/analyzer.ts +122 -0
- package/src/commands/build/client/analyzer.tsx +121 -0
- package/src/commands/build/client/index.ts +28 -0
- package/src/commands/build.ts +29 -155
- package/src/commands/utils/optionParser.ts +4 -0
- package/src/rollup/base.ts +11 -0
- package/src/rollup/index.ts +54 -4
- package/src/server.ts +9 -1
- package/src/utils/checkDependency.ts +22 -0
- package/src/utils/getExports.ts +26 -16
- package/src/utils/ts.ts +3 -3
package/dist/rollup/index.js
CHANGED
@@ -4155,8 +4155,7 @@ function bundleAnalyzer(modulesResolved) {
|
|
4155
4155
|
return {
|
4156
4156
|
name: "jiek:bundle-analyzer",
|
4157
4157
|
async closeBundle(...args) {
|
4158
|
-
if (typeof ana.closeBundle !== "function")
|
4159
|
-
return;
|
4158
|
+
if (typeof ana.closeBundle !== "function") return;
|
4160
4159
|
return ana.closeBundle?.call(this, ...args);
|
4161
4160
|
}
|
4162
4161
|
};
|
@@ -4238,14 +4237,24 @@ function getExports({
|
|
4238
4237
|
}
|
4239
4238
|
);
|
4240
4239
|
const crossModuleWithConditional = crossModuleConvertor ? {
|
4241
|
-
import: (opts) =>
|
4242
|
-
|
4243
|
-
|
4244
|
-
|
4245
|
-
|
4246
|
-
|
4247
|
-
|
4248
|
-
|
4240
|
+
import: (opts) => {
|
4241
|
+
if (pkgIsModule) return false;
|
4242
|
+
if (opts.src.endsWith(".cts")) return false;
|
4243
|
+
if (intersection(
|
4244
|
+
new Set(opts.conditionals),
|
4245
|
+
/* @__PURE__ */ new Set(["import", "module"])
|
4246
|
+
).size !== 0) return false;
|
4247
|
+
return opts.dist.replace(/\.js$/, ".mjs");
|
4248
|
+
},
|
4249
|
+
require: (opts) => {
|
4250
|
+
if (!pkgIsModule) return false;
|
4251
|
+
if (opts.src.endsWith(".mts")) return false;
|
4252
|
+
if (intersection(
|
4253
|
+
new Set(opts.conditionals),
|
4254
|
+
/* @__PURE__ */ new Set(["require", "node"])
|
4255
|
+
).size !== 0) return false;
|
4256
|
+
return opts.dist.replace(/\.js$/, ".cjs");
|
4257
|
+
}
|
4249
4258
|
} : {};
|
4250
4259
|
return [
|
4251
4260
|
filteredResolvedEntrypoints,
|
@@ -4264,8 +4273,7 @@ function getExports({
|
|
4264
4273
|
|
4265
4274
|
let root;
|
4266
4275
|
function getRoot() {
|
4267
|
-
if (root)
|
4268
|
-
return root;
|
4276
|
+
if (root) return root;
|
4269
4277
|
const rootOption = process.env.JIEK_ROOT;
|
4270
4278
|
root = rootOption ? path.isAbsolute(rootOption) ? rootOption : path.resolve(process.cwd(), rootOption) : void 0;
|
4271
4279
|
return root;
|
@@ -4282,8 +4290,7 @@ try {
|
|
4282
4290
|
let wd;
|
4283
4291
|
let notWorkspace = false;
|
4284
4292
|
function getWD() {
|
4285
|
-
if (wd)
|
4286
|
-
return { wd, notWorkspace };
|
4293
|
+
if (wd) return { wd, notWorkspace };
|
4287
4294
|
const root = getRoot();
|
4288
4295
|
if (root !== void 0) {
|
4289
4296
|
const isWorkspace = isWorkspaceDir(root, type);
|
@@ -4405,16 +4412,14 @@ function loadConfig(dirOrOptions) {
|
|
4405
4412
|
default:
|
4406
4413
|
throw new Error(`unsupported config file type: ${ext}`);
|
4407
4414
|
}
|
4408
|
-
if (!module)
|
4409
|
-
throw new Error("config file is empty");
|
4415
|
+
if (!module) throw new Error("config file is empty");
|
4410
4416
|
return module.default ?? module;
|
4411
4417
|
}
|
4412
4418
|
|
4413
4419
|
const recusiveListFiles = (dir) => fs.readdirSync(dir).reduce((acc, file) => {
|
4414
4420
|
const filePath = resolve(dir, file);
|
4415
4421
|
if (fs.statSync(filePath).isDirectory()) {
|
4416
|
-
if (filePath.endsWith("/node_modules"))
|
4417
|
-
return acc;
|
4422
|
+
if (filePath.endsWith("/node_modules")) return acc;
|
4418
4423
|
return [...acc, ...recusiveListFiles(filePath)];
|
4419
4424
|
}
|
4420
4425
|
return [...acc, filePath];
|
@@ -4427,10 +4432,9 @@ const getExtendTSConfig = (tsconfigPath) => {
|
|
4427
4432
|
const { extends: exts, ...tsconfig } = getTSConfig(tsconfigPath);
|
4428
4433
|
const resolvePaths = (paths) => paths?.map((p) => resolve(tsconfigPathDirname, p)) ?? [];
|
4429
4434
|
const extendsPaths = resolvePaths(
|
4430
|
-
exts ? Array.isArray(exts) ? exts : [exts] : []
|
4435
|
+
exts !== void 0 ? Array.isArray(exts) ? exts : [exts] : []
|
4431
4436
|
);
|
4432
|
-
if (extendsPaths.length === 0)
|
4433
|
-
return tsconfig;
|
4437
|
+
if (extendsPaths.length === 0) return tsconfig;
|
4434
4438
|
return extendsPaths.map(getExtendTSConfig).concat(tsconfig).reduce((acc, { compilerOptions = {}, references: _, ...curr }) => ({
|
4435
4439
|
...acc,
|
4436
4440
|
...curr,
|
@@ -4457,24 +4461,20 @@ const getCompilerOptionsByFilePath = (tsconfigPath, filePath) => {
|
|
4457
4461
|
tsconfig.include,
|
4458
4462
|
tsconfig.exclude
|
4459
4463
|
].map(resolvePaths);
|
4460
|
-
if (exclude.length > 0 && exclude.some((i) => micromatchExports.isMatch(filePath, i)))
|
4461
|
-
|
4462
|
-
if (tsconfig.files?.length === 0 && tsconfig.include?.length === 0)
|
4463
|
-
return;
|
4464
|
+
if (exclude.length > 0 && exclude.some((i) => micromatchExports.isMatch(filePath, i))) return;
|
4465
|
+
if (tsconfig.files?.length === 0 && tsconfig.include?.length === 0) return;
|
4464
4466
|
let isInclude = false;
|
4465
4467
|
isInclude || (isInclude = files.length > 0 && files.includes(filePath));
|
4466
4468
|
isInclude || (isInclude = include.length > 0 && include.some((i) => micromatchExports.isMatch(filePath, i)));
|
4467
4469
|
if (isInclude) {
|
4468
4470
|
return tsconfig.compilerOptions ?? {};
|
4469
4471
|
} else {
|
4470
|
-
if (tsconfig.files && tsconfig.files.length > 0 || tsconfig.include && tsconfig.include.length > 0)
|
4471
|
-
return;
|
4472
|
+
if (tsconfig.files && tsconfig.files.length > 0 || tsconfig.include && tsconfig.include.length > 0) return;
|
4472
4473
|
}
|
4473
4474
|
references.reverse();
|
4474
4475
|
for (const ref of references) {
|
4475
4476
|
const compilerOptions = getCompilerOptionsByFilePath(ref, filePath);
|
4476
|
-
if (compilerOptions)
|
4477
|
-
return compilerOptions;
|
4477
|
+
if (compilerOptions) return compilerOptions;
|
4478
4478
|
}
|
4479
4479
|
return tsconfig.compilerOptions;
|
4480
4480
|
};
|
@@ -4653,10 +4653,8 @@ const resolveOutputControls = (context, output) => ({
|
|
4653
4653
|
const resolveWorkspacePath = (p) => resolve(WORKSPACE_ROOT, p);
|
4654
4654
|
const pascalCase = (str) => str.replace(/[@|/-](\w)/g, (_, $1) => $1.toUpperCase()).replace(/(?:^|-)(\w)/g, (_, $1) => $1.toUpperCase());
|
4655
4655
|
const reveal = (obj, keys) => keys.reduce((acc, key) => {
|
4656
|
-
if (typeof acc === "string")
|
4657
|
-
|
4658
|
-
if (!(key in acc))
|
4659
|
-
throw new Error(`key ${key} not found in exports`);
|
4656
|
+
if (typeof acc === "string") throw new Error("key not found in exports");
|
4657
|
+
if (!(key in acc)) throw new Error(`key ${key} not found in exports`);
|
4660
4658
|
return acc[key];
|
4661
4659
|
}, obj);
|
4662
4660
|
const resolveMinifyOptions = (minifyOptions) => typeof minifyOptions === "string" ? { type: minifyOptions } : minifyOptions ?? { type: "esbuild" };
|
@@ -4676,7 +4674,7 @@ const withMinify = (output, onlyOncePlugins = []) => {
|
|
4676
4674
|
const minifyPlugin = resolvedMinifyOptions.type === "esbuild" ? import('rollup-plugin-esbuild').then(({ minify: minify2 }) => minify2(noTypeResolvedMinifyOptions)) : resolvedMinifyOptions.type === "swc" ? import('rollup-plugin-swc3').then(({ minify: minify2 }) => minify2(noTypeResolvedMinifyOptions)) : import('@rollup/plugin-terser').then(({ default: minify2 }) => minify2(noTypeResolvedMinifyOptions));
|
4677
4675
|
return minify === "only-minify" ? [{
|
4678
4676
|
...output,
|
4679
|
-
// TODO replace suffix when
|
4677
|
+
// TODO replace suffix when publish to npm and the `build.output.minify` is 'only-minify'
|
4680
4678
|
// TODO resolve dts output file name
|
4681
4679
|
entryFileNames: (chunkInfo) => typeof output.entryFileNames === "function" ? output.entryFileNames(chunkInfo) : (() => {
|
4682
4680
|
throw new Error("entryFileNames must be a function");
|
@@ -4783,15 +4781,48 @@ const generateConfigs = (context, options = {}) => {
|
|
4783
4781
|
const { js: jsOutput, dts: dtsOutput } = resolveOutputControls(context, build.output);
|
4784
4782
|
const rollupOptions = [];
|
4785
4783
|
const commonPlugins = [
|
4786
|
-
nodeResolve({
|
4784
|
+
nodeResolve({
|
4785
|
+
exportConditions,
|
4786
|
+
extensions: [
|
4787
|
+
".js",
|
4788
|
+
".cjs",
|
4789
|
+
".mjs",
|
4790
|
+
".jsx",
|
4791
|
+
".cjsx",
|
4792
|
+
".mjsx",
|
4793
|
+
".ts",
|
4794
|
+
".cts",
|
4795
|
+
".mts",
|
4796
|
+
".tsx",
|
4797
|
+
".ctsx",
|
4798
|
+
".mtsx"
|
4799
|
+
]
|
4800
|
+
})
|
4787
4801
|
];
|
4788
4802
|
if (jsOutput && !WITHOUT_JS) {
|
4789
4803
|
const sourcemap = typeof options?.output?.sourcemap === "object" ? options.output.sourcemap.js : options?.output?.sourcemap;
|
4804
|
+
const features = Object.assign({
|
4805
|
+
keepImportAttributes: true
|
4806
|
+
}, build.features);
|
4790
4807
|
const builder = resolvedBuilderOptions.type === "esbuild" ? import('rollup-plugin-esbuild').then(
|
4791
4808
|
({ default: esbuild }) => esbuild({
|
4792
4809
|
sourceMap: sourcemap === "hidden" ? false : !!sourcemap,
|
4793
4810
|
tsconfig: buildTSConfigPath,
|
4794
|
-
|
4811
|
+
loaders: {
|
4812
|
+
cts: "ts",
|
4813
|
+
ctsx: "tsx",
|
4814
|
+
mts: "ts",
|
4815
|
+
mtsx: "tsx",
|
4816
|
+
cjs: "js",
|
4817
|
+
cjsx: "jsx",
|
4818
|
+
mjs: "js",
|
4819
|
+
mjsx: "jsx"
|
4820
|
+
},
|
4821
|
+
...noTypeResolvedBuilderOptions,
|
4822
|
+
supported: {
|
4823
|
+
"import-attributes": features.keepImportAttributes !== false,
|
4824
|
+
...resolvedBuilderOptions.supported
|
4825
|
+
}
|
4795
4826
|
})
|
4796
4827
|
) : import('rollup-plugin-swc3').then(
|
4797
4828
|
({ default: swc }) => swc({
|
@@ -4800,7 +4831,14 @@ const generateConfigs = (context, options = {}) => {
|
|
4800
4831
|
inline: "inline"
|
4801
4832
|
}[sourcemap] ?? void 0,
|
4802
4833
|
tsconfig: buildTSConfigPath,
|
4803
|
-
...noTypeResolvedBuilderOptions
|
4834
|
+
...noTypeResolvedBuilderOptions,
|
4835
|
+
jsc: {
|
4836
|
+
...resolvedBuilderOptions.jsc,
|
4837
|
+
experimental: {
|
4838
|
+
...resolvedBuilderOptions.jsc?.experimental,
|
4839
|
+
keepImportAttributes: features.keepImportAttributes !== false
|
4840
|
+
}
|
4841
|
+
}
|
4804
4842
|
})
|
4805
4843
|
);
|
4806
4844
|
const [ana, anaOutputPlugin] = bundleAnalyzer((modules) => void publishInEntry("modulesAnalyze", { modules }));
|
@@ -4819,6 +4857,8 @@ const generateConfigs = (context, options = {}) => {
|
|
4819
4857
|
sourcemap,
|
4820
4858
|
format,
|
4821
4859
|
strict: typeof options?.output?.strict === "object" ? options.output.strict.js : options?.output?.strict,
|
4860
|
+
externalImportAttributes: features.keepImportAttributes !== false,
|
4861
|
+
importAttributesKey: features.keepImportAttributes === false || features.keepImportAttributes === void 0 ? void 0 : features.keepImportAttributes === true ? "with" : features.keepImportAttributes,
|
4822
4862
|
plugins: [
|
4823
4863
|
isFormatEsm(format === "esm")
|
4824
4864
|
]
|
@@ -4894,10 +4934,8 @@ const generateConfigs = (context, options = {}) => {
|
|
4894
4934
|
function template(packageJSON) {
|
4895
4935
|
const { name, type, exports: entrypoints } = packageJSON;
|
4896
4936
|
const pkgIsModule = type === "module";
|
4897
|
-
if (!name)
|
4898
|
-
|
4899
|
-
if (!entrypoints)
|
4900
|
-
throw new Error("package.json exports is required");
|
4937
|
+
if (!name) throw new Error("package.json name is required");
|
4938
|
+
if (!entrypoints) throw new Error("package.json exports is required");
|
4901
4939
|
const packageName = pascalCase(name);
|
4902
4940
|
const external = externalResolver(packageJSON);
|
4903
4941
|
const [filteredResolvedEntrypoints, exports] = getExports({
|
@@ -4917,6 +4955,7 @@ function template(packageJSON) {
|
|
4917
4955
|
}
|
4918
4956
|
return false;
|
4919
4957
|
});
|
4958
|
+
console.log(exports);
|
4920
4959
|
const configs = [];
|
4921
4960
|
leafMap.forEach(
|
4922
4961
|
(keysArr, input) => keysArr.forEach((keys) => {
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "jiek",
|
3
3
|
"type": "module",
|
4
|
-
"version": "2.2.1",
|
4
|
+
"version": "2.2.3-alpha.1",
|
5
5
|
"description": "A lightweight toolkit for compiling and managing libraries based on `package.json` metadata and suitable for `Monorepo`.",
|
6
6
|
"author": "YiJie <yijie4188@gmail.com>",
|
7
7
|
"homepage": "https://github.com/NWYLZW/jiek/tree/master/packages/jiek#readme",
|
@@ -48,7 +48,11 @@
|
|
48
48
|
}
|
49
49
|
},
|
50
50
|
"imports": {
|
51
|
-
"#~/*":
|
51
|
+
"#~/*": [
|
52
|
+
"./src/*",
|
53
|
+
"./src/*/index.ts",
|
54
|
+
"./src/*/index.tsx"
|
55
|
+
]
|
52
56
|
},
|
53
57
|
"bin": {
|
54
58
|
"jiek": "bin/jiek.js",
|
@@ -57,7 +61,7 @@
|
|
57
61
|
"jb": "bin/jiek-build.js"
|
58
62
|
},
|
59
63
|
"peerDependencies": {
|
60
|
-
"@pnpm/filter-workspace-packages": "^7.2.13||^8.0.0||^9.0.0||^10.0.0",
|
64
|
+
"@pnpm/filter-workspace-packages": "^7.2.13||^8.0.0||^9.0.0||^10.0.0||>=1000.0.0",
|
61
65
|
"@rollup/plugin-terser": "^0.4.4",
|
62
66
|
"esbuild-register": "^3.5.0",
|
63
67
|
"postcss": "^8.4.47",
|
@@ -65,7 +69,7 @@
|
|
65
69
|
"rollup-plugin-postcss": "^4.0.2",
|
66
70
|
"rollup-plugin-swc3": "^0.12.1",
|
67
71
|
"typescript": "^4.0.0||^5.0.0",
|
68
|
-
"vite-bundle-analyzer": "
|
72
|
+
"vite-bundle-analyzer": "0.16.0-beta.1"
|
69
73
|
},
|
70
74
|
"dependencies": {
|
71
75
|
"@inquirer/prompts": "^7.1.0",
|
@@ -83,8 +87,8 @@
|
|
83
87
|
"jsonc-parser": "^3.2.1",
|
84
88
|
"koa": "^2.15.3",
|
85
89
|
"rollup": "^4.0.0",
|
86
|
-
"@jiek/
|
87
|
-
"@jiek/
|
90
|
+
"@jiek/pkger": "^0.2.1",
|
91
|
+
"@jiek/utils": "^0.2.3"
|
88
92
|
},
|
89
93
|
"peerDependenciesMeta": {
|
90
94
|
"@pnpm/filter-workspace-packages": {
|
@@ -0,0 +1,122 @@
|
|
1
|
+
import type { Command } from 'commander'
|
2
|
+
|
3
|
+
import { CLIENT_CUSTOM_RENDER_SCRIPT } from '#~/commands/build/client/index.ts'
|
4
|
+
import { parseBoolean } from '#~/commands/utils/optionParser.ts'
|
5
|
+
import type { Module } from '#~/rollup/bundle-analyzer.ts'
|
6
|
+
import type { createServer } from '#~/server.ts'
|
7
|
+
import { checkDependency } from '#~/utils/checkDependency.ts'
|
8
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
|
9
|
+
import path from 'node:path'
|
10
|
+
|
11
|
+
export interface AnalyzerBuildOptions {
|
12
|
+
ana?: boolean
|
13
|
+
/**
|
14
|
+
* @default '.jk-analyses'
|
15
|
+
*/
|
16
|
+
'ana.dir': string
|
17
|
+
/**
|
18
|
+
* @default 'server'
|
19
|
+
*/
|
20
|
+
'ana.mode': string
|
21
|
+
'ana.open'?: boolean
|
22
|
+
/**
|
23
|
+
* @default 'parsed'
|
24
|
+
*/
|
25
|
+
'ana.size': string
|
26
|
+
}
|
27
|
+
|
28
|
+
export const registerAnalyzerCommandOptions = (command: Command) =>
|
29
|
+
command
|
30
|
+
.option('--ana', 'Enable the bundle analyzer.', parseBoolean)
|
31
|
+
.option('--ana.dir <DIR>', 'The directory of the bundle analyzer.', '.jk-analyses')
|
32
|
+
.option(
|
33
|
+
'--ana.mode <MODE>',
|
34
|
+
'The mode of the bundle analyzer, support "static", "json" and "server".',
|
35
|
+
'server'
|
36
|
+
)
|
37
|
+
.option('--ana.open', 'Open the bundle analyzer in the browser.', parseBoolean)
|
38
|
+
.option(
|
39
|
+
'--ana.size <SIZE>',
|
40
|
+
'The default size of the bundle analyzer, support "stat", "parsed" and "gzip".',
|
41
|
+
'parsed'
|
42
|
+
)
|
43
|
+
|
44
|
+
export const useAnalyzer = async (options: AnalyzerBuildOptions, server?: ReturnType<typeof createServer>) => {
|
45
|
+
const modules: Module[] = []
|
46
|
+
let bundleAnalyzerModule: typeof import('vite-bundle-analyzer') | undefined
|
47
|
+
const analyzer = options.ana
|
48
|
+
? {
|
49
|
+
dir: options['ana.dir'],
|
50
|
+
mode: options['ana.mode'],
|
51
|
+
open: options['ana.open'],
|
52
|
+
size: options['ana.size']
|
53
|
+
}
|
54
|
+
: undefined
|
55
|
+
if (
|
56
|
+
options.ana
|
57
|
+
&& ![
|
58
|
+
'stat',
|
59
|
+
'parsed',
|
60
|
+
'gzip'
|
61
|
+
].includes(analyzer?.size ?? '')
|
62
|
+
) {
|
63
|
+
throw new Error('The value of `ana.size` must be "stat", "parsed" or "gzip"')
|
64
|
+
}
|
65
|
+
|
66
|
+
if (analyzer) {
|
67
|
+
await checkDependency('vite-bundle-analyzer')
|
68
|
+
bundleAnalyzerModule = await import('vite-bundle-analyzer')
|
69
|
+
}
|
70
|
+
|
71
|
+
const refreshAnalyzer = async (cwd: string, applyModules: typeof modules) => {
|
72
|
+
if (!(analyzer && server && bundleAnalyzerModule)) return
|
73
|
+
|
74
|
+
if (analyzer.mode === 'json') {
|
75
|
+
const anaDir = path.resolve(cwd, analyzer.dir)
|
76
|
+
if (!existsSync(anaDir)) {
|
77
|
+
mkdirSync(anaDir, { recursive: true })
|
78
|
+
}
|
79
|
+
const gitIgnorePath = path.resolve(anaDir, '.gitignore')
|
80
|
+
if (!existsSync(gitIgnorePath)) {
|
81
|
+
writeFileSync(gitIgnorePath, '*\n!.gitignore\n')
|
82
|
+
}
|
83
|
+
const npmIgnorePath = path.resolve(anaDir, '.npmignore')
|
84
|
+
if (!existsSync(npmIgnorePath)) {
|
85
|
+
writeFileSync(npmIgnorePath, '*\n')
|
86
|
+
}
|
87
|
+
if (!statSync(anaDir).isDirectory()) {
|
88
|
+
throw new Error(`The directory '${anaDir}' is not a directory.`)
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
const { renderView, injectHTMLTag } = bundleAnalyzerModule
|
93
|
+
applyModules.forEach(m => {
|
94
|
+
const index = modules.findIndex(({ filename }) => filename === m.filename)
|
95
|
+
if (index === -1) {
|
96
|
+
modules.push(m)
|
97
|
+
} else {
|
98
|
+
modules[index] = m
|
99
|
+
}
|
100
|
+
})
|
101
|
+
let html = await renderView(modules, {
|
102
|
+
title: `Jiek Analyzer`,
|
103
|
+
mode: analyzer.size as 'stat' | 'parsed' | 'gzip'
|
104
|
+
})
|
105
|
+
html = injectHTMLTag({
|
106
|
+
html,
|
107
|
+
injectTo: 'body',
|
108
|
+
descriptors: [
|
109
|
+
{ kind: 'script', text: CLIENT_CUSTOM_RENDER_SCRIPT }
|
110
|
+
]
|
111
|
+
})
|
112
|
+
void server.renderTo('/ana', html)
|
113
|
+
}
|
114
|
+
|
115
|
+
return {
|
116
|
+
modules,
|
117
|
+
refreshAnalyzer,
|
118
|
+
ANALYZER_ENV: {
|
119
|
+
JIEK_ANALYZER: analyzer ? JSON.stringify(analyzer) : undefined
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import type { Module } from '#~/rollup/bundle-analyzer.ts'
|
2
|
+
|
3
|
+
interface Node {
|
4
|
+
id: string
|
5
|
+
filename: string
|
6
|
+
parent?: Node
|
7
|
+
}
|
8
|
+
|
9
|
+
declare global {
|
10
|
+
// @ts-ignore
|
11
|
+
// eslint-disable-next-line no-var,vars-on-top
|
12
|
+
var React: typeof import('react')
|
13
|
+
// eslint-disable-next-line no-var,vars-on-top
|
14
|
+
var analyzeModule: Module[]
|
15
|
+
interface WindowEventMap {
|
16
|
+
'graph:click': CustomEvent<
|
17
|
+
| undefined
|
18
|
+
| { node: Node }
|
19
|
+
>
|
20
|
+
'send:filter': CustomEvent<{
|
21
|
+
analyzeModule: Module[]
|
22
|
+
}>
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
export function Main() {
|
27
|
+
const { useState, useMemo, useEffect, useCallback } = React
|
28
|
+
const [path, setPath] = useState(() => location.pathname.replace(/^\/ana\/?/, ''))
|
29
|
+
const [pkgName, entry] = useMemo(() => {
|
30
|
+
const pkgName = /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(path)?.[1]
|
31
|
+
return [
|
32
|
+
pkgName,
|
33
|
+
(pkgName != null) ? path.replace(`${pkgName}/`, '') : undefined
|
34
|
+
]
|
35
|
+
}, [path])
|
36
|
+
const push = useCallback((newPath: string) => {
|
37
|
+
setPath(newPath)
|
38
|
+
document.title = `${document.title.replace(/ - \/.*/, '')} - \/${newPath}`
|
39
|
+
history.pushState(null, '', `/ana/${newPath}`)
|
40
|
+
}, [])
|
41
|
+
const filterModules = useCallback((startWith: string) => {
|
42
|
+
const modules = analyzeModule.filter(m => m.filename.startsWith(startWith))
|
43
|
+
dispatchEvent(new CustomEvent('send:filter', { detail: { analyzeModule: modules } }))
|
44
|
+
}, [])
|
45
|
+
useEffect(() => {
|
46
|
+
if (path !== '') {
|
47
|
+
document.title = `${document.title.replace(/ - \/.*/, '')} - \/${path}`
|
48
|
+
} else {
|
49
|
+
document.title = document.title.replace(/ - \/.*/, '')
|
50
|
+
}
|
51
|
+
filterModules(path)
|
52
|
+
}, [path, filterModules])
|
53
|
+
useEffect(() => {
|
54
|
+
const offGraphClick = listen('graph:click', ({ detail }) => {
|
55
|
+
if (!detail) return
|
56
|
+
|
57
|
+
let root = detail.node
|
58
|
+
while (root.parent) {
|
59
|
+
root = root.parent
|
60
|
+
}
|
61
|
+
if (root.filename === path) return
|
62
|
+
push(root.filename)
|
63
|
+
})
|
64
|
+
return () => {
|
65
|
+
offGraphClick()
|
66
|
+
}
|
67
|
+
}, [push])
|
68
|
+
function listen<T extends keyof WindowEventMap>(type: T, listener: (this: Window, ev: WindowEventMap[T]) => any) {
|
69
|
+
window.addEventListener(type, listener)
|
70
|
+
return () => {
|
71
|
+
window.removeEventListener(type, listener)
|
72
|
+
}
|
73
|
+
}
|
74
|
+
return (
|
75
|
+
<div
|
76
|
+
style={{
|
77
|
+
padding: '12px 55px'
|
78
|
+
}}
|
79
|
+
>
|
80
|
+
/
|
81
|
+
<select
|
82
|
+
style={{
|
83
|
+
appearance: 'none',
|
84
|
+
border: 'none',
|
85
|
+
background: 'none'
|
86
|
+
}}
|
87
|
+
value={pkgName}
|
88
|
+
onChange={e => push(e.target.value)}
|
89
|
+
>
|
90
|
+
<option value=''>All</option>
|
91
|
+
{analyzeModule
|
92
|
+
.map(m => /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(m.filename)?.[1])
|
93
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
94
|
+
.map(v => (
|
95
|
+
<option key={v} value={v}>{v}</option>
|
96
|
+
))}
|
97
|
+
</select>
|
98
|
+
{pkgName != null && <>
|
99
|
+
/
|
100
|
+
<select
|
101
|
+
style={{
|
102
|
+
appearance: 'none',
|
103
|
+
border: 'none',
|
104
|
+
background: 'none'
|
105
|
+
}}
|
106
|
+
value={entry}
|
107
|
+
onChange={e => push(`${pkgName}/${e.target.value}`)}
|
108
|
+
>
|
109
|
+
<option value=''>All</option>
|
110
|
+
{analyzeModule
|
111
|
+
.filter(m => m.filename.startsWith(`${pkgName}/`))
|
112
|
+
.map(m => m.filename.replace(`${pkgName}/`, ''))
|
113
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
114
|
+
.map(v => (
|
115
|
+
<option key={v} value={v}>{v}</option>
|
116
|
+
))}
|
117
|
+
</select>
|
118
|
+
</>}
|
119
|
+
</div>
|
120
|
+
)
|
121
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { Main } from './analyzer'
|
2
|
+
|
3
|
+
declare global {
|
4
|
+
// eslint-disable-next-line no-var,vars-on-top
|
5
|
+
var CUSTOM_SIDE_BAR: boolean
|
6
|
+
// eslint-disable-next-line no-var,vars-on-top
|
7
|
+
var __REPLACE_INJECT__: string
|
8
|
+
}
|
9
|
+
|
10
|
+
function render() {
|
11
|
+
CUSTOM_SIDE_BAR = true
|
12
|
+
window.addEventListener('client:ready', () =>
|
13
|
+
setTimeout(() => {
|
14
|
+
window.dispatchEvent(
|
15
|
+
new CustomEvent('send:ui', {
|
16
|
+
detail: { type: 'Main', Component: __REPLACE_INJECT__ }
|
17
|
+
})
|
18
|
+
)
|
19
|
+
}, 0))
|
20
|
+
}
|
21
|
+
|
22
|
+
export const CLIENT_CUSTOM_RENDER_SCRIPT = [
|
23
|
+
Main.toString(),
|
24
|
+
render
|
25
|
+
.toString()
|
26
|
+
.replace('__REPLACE_INJECT__', Main.name),
|
27
|
+
`(${render.name})()`
|
28
|
+
].join('\n')
|