buner 1.0.5 → 1.0.6

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.
@@ -13,18 +13,18 @@ import { globby } from "globby";
13
13
  import { exec } from "node:child_process";
14
14
  import validateProjectName from "validate-npm-package-name";
15
15
  const name = "buner";
16
- const version = "1.0.5";
16
+ const version = "1.0.6";
17
17
  const description = "Frontend build toolkit for Vite + React SSR projects — SCSS pipeline, prerender, SSR dev server, and backend integration.";
18
18
  const type = "module";
19
19
  const license = "MIT";
20
20
  const repository = { "type": "git", "url": "https://github.com/precise-alloy/buner.git" };
21
21
  const homepage = "https://www.npmjs.com/package/buner";
22
22
  const keywords = ["vite", "react", "ssr", "scss", "prerender", "frontend", "build-tool", "cli"];
23
- const bin$1 = { "buner": "./bin/buner.js" };
24
- const files = ["bin", "cli", "xpack", "public", "server.ts", "prerender.ts", "integration.ts", "styles.ts", "scripts.ts", "states.ts", "migrate-scss.ts", "vite.config.ts", "index.html", "tsconfig.json", "eslint.config.mjs", "types.d.ts", ".env", ".env.development", ".env.eshn", "README.md"];
23
+ const bin$1 = { "buner": "./dist/buner.js" };
24
+ const files = ["dist", "xpack", "public", "vite.config.ts", "index.html", "tsconfig.json", "eslint.config.mjs", "types.d.ts", ".env", ".env.development", ".env.eshn", "README.md"];
25
25
  const scripts = { "start": "bun run dev", "predev": "bun upgrade", "dev": 'concurrently --kill-others "bun styles.ts --watch" "bun states.ts --watch" "cross-env scriptOnly=true vite build --mode development --watch" "bun server.ts --mode development"', "serve": "bun server.ts", "watch": "bun server.ts", "build": "bun run build:static && bun run build:server", "build:eshn": "bun run build:static:eshn && bun run build:server:eshn", "preview": "vite preview", "build:server": "vite build --ssr src/entry-server.tsx --outDir dist/server", "build:server:eshn": "vite build --ssr src/entry-server.tsx --outDir dist/server --mode eshn", "build:static": "vite build --outDir dist/static", "build:static:eshn": "vite build --outDir dist/static --mode eshn", "generate": "bun states.ts && bun run styles && bun run build && bun prerender.ts --add-hash", "eshn": "bun states.ts && bun run styles && bun run build:eshn && bun prerender.ts --add-hash --mode eshn", "inte": "bun run styles && bun run build && bun prerender.ts && bun integration.ts", "styles": "bun styles.ts", "format": "prettier --write .", "lint": "eslint --fix", "cli:start": "vite build -c vite.cli.config.ts --watch", "cli:build": "vite build -c vite.cli.config.ts" };
26
26
  const engines = { "node": ">=20.0.0" };
27
- const dependencies = { "@vitejs/plugin-react": "^5.1.4", "autoprefixer": "^10.4.27", "chalk": "^5.5.0", "cheerio": "^1.2.0", "chokidar": "^4.0.3", "commander": "^14.0.3", "concurrently": "^9.2.0", "cross-env": "^10.1.0", "cssnano": "^7.1.0", "debounce": "^3.0.0", "express": "^5.2.1", "glob": "^13.0.6", "globby": "^16.1.1", "js-beautify": "^1.15.4", "lodash": "^4.17.21", "magic-string": "^0.30.17", "node-fetch": "^3.3.2", "postcss": "^8.5.8", "prompts": "^2.4.2", "sass": "^1.89.2", "slash": "^5.1.0", "tsx": "^4.19.0", "validate-npm-package-name": "^7.0.0", "vite": "^7.0.6" };
27
+ const dependencies = { "@vitejs/plugin-react": "^5.1.4", "autoprefixer": "^10.4.27", "chalk": "^5.5.0", "cheerio": "^1.2.0", "chokidar": "^4.0.3", "commander": "^14.0.3", "concurrently": "^9.2.0", "cross-env": "^10.1.0", "cssnano": "^7.1.0", "debounce": "^3.0.0", "express": "^5.2.1", "glob": "^13.0.6", "globby": "^16.1.1", "js-beautify": "^1.15.4", "lodash": "^4.17.21", "magic-string": "^0.30.17", "node-fetch": "^3.3.2", "postcss": "^8.5.8", "prompts": "^2.4.2", "sass": "^1.89.2", "slash": "^5.1.0", "validate-npm-package-name": "^7.0.0", "vite": "^7.0.6" };
28
28
  const peerDependencies = { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "react-router-dom": "^6.0.0 || ^7.0.0" };
29
29
  const devDependencies = { "@eslint/compat": "^2.0.0", "@next/eslint-plugin-next": "^16.0.8", "@types/css": "^0.0.38", "@types/debounce": "^1.2.4", "@types/express": "^5.0.6", "@types/js-beautify": "^1.14.3", "@types/lodash": "^4.17.24", "@types/node": "^24.11.0", "@types/prettier": "^3.0.0", "@types/prompts": "^2.4.9", "@types/react": "^19.2.14", "@types/react-dom": "^19.1.7", "@types/validate-npm-package-name": "^4.0.2", "@typescript-eslint/eslint-plugin": "^8.50.0", "@typescript-eslint/parser": "^8.50.0", "css": "^3.0.0", "eslint": "^9.39.2", "eslint-config-next": "^16.0.8", "eslint-config-prettier": "10.1.8", "eslint-plugin-import": "2.32.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-node": "11.1.0", "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-unused-imports": "^4.4.1", "globals": "^16.3.0", "msw": "^2.12.10", "postcss-scss": "^4.0.9", "prettier": "^3.6.2", "react": "^19.2.4", "react-dom": "^19.2.4", "react-router-dom": "^7.13.1", "rollup": "^4.59.0", "svgo": "^4.0.0" };
30
30
  const msw = { "workerDirectory": "public" };
@@ -430,11 +430,12 @@ function validateNpmName(name2) {
430
430
  }
431
431
  const { green, yellow, bold, cyan, red } = chalk;
432
432
  const packageName = "buner";
433
- const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
433
+ const packageDir = path.dirname(fileURLToPath(import.meta.url));
434
434
  const pkg = (file) => path.join(packageDir, file);
435
435
  const bin = (name2) => {
436
436
  const ext = process.platform === "win32" ? ".cmd" : "";
437
- const local = path.join(packageDir, "node_modules", ".bin", name2 + ext);
437
+ const pkgRoot = path.resolve(packageDir, "..");
438
+ const local = path.join(pkgRoot, "node_modules", ".bin", name2 + ext);
438
439
  try {
439
440
  if (require("fs").existsSync(local)) return local;
440
441
  } catch {
@@ -529,57 +530,62 @@ For example:
529
530
  await notifyUpdate();
530
531
  });
531
532
  program.command("dev").description("Start development mode with all watchers").action(async () => {
533
+ const viteConfig = path.resolve(packageDir, "..", "vite.config.ts");
532
534
  await run(bin("concurrently"), [
533
535
  "--kill-others",
534
- `"${bin("tsx")} ${pkg("styles.ts")} --watch"`,
535
- `"${bin("tsx")} ${pkg("states.ts")} --watch"`,
536
- `"${bin("cross-env")} scriptOnly=true ${bin("vite")} build --config ${pkg("vite.config.ts")} --mode development --watch"`,
537
- `"${bin("tsx")} ${pkg("server.ts")} --mode development"`
536
+ `"node ${pkg("styles.js")} --watch"`,
537
+ `"node ${pkg("states.js")} --watch"`,
538
+ `"${bin("cross-env")} scriptOnly=true ${bin("vite")} build --config ${viteConfig} --mode development --watch"`,
539
+ `"node ${pkg("server.js")} --mode development"`
538
540
  ]);
539
541
  });
540
542
  program.command("serve").description("Start the SSR dev server").option("--mode <mode>", "server mode", "development").action(async (opts) => {
541
- await run(bin("tsx"), [pkg("server.ts"), "--mode", opts.mode]);
543
+ await run("node", [pkg("server.js"), "--mode", opts.mode]);
542
544
  });
543
545
  program.command("build").description("Build the project (static + SSR)").action(async () => {
544
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --outDir dist/static`);
545
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --ssr src/entry-server.tsx --outDir dist/server`);
546
+ const viteConfig = path.resolve(packageDir, "..", "vite.config.ts");
547
+ runSync(`${bin("vite")} build --config ${viteConfig} --outDir dist/static`);
548
+ runSync(`${bin("vite")} build --config ${viteConfig} --ssr src/entry-server.tsx --outDir dist/server`);
546
549
  });
547
550
  program.command("generate").description("Full static site generation (states + styles + build + prerender)").option("--mode <mode>", "build mode", "production").action(async (opts) => {
548
- runSync(`${bin("tsx")} ${pkg("states.ts")}`);
549
- runSync(`${bin("tsx")} ${pkg("styles.ts")}`);
551
+ const viteConfig = path.resolve(packageDir, "..", "vite.config.ts");
552
+ runSync(`node ${pkg("states.js")}`);
553
+ runSync(`node ${pkg("styles.js")}`);
550
554
  if (opts.mode === "production") {
551
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --outDir dist/static`);
552
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --ssr src/entry-server.tsx --outDir dist/server`);
555
+ runSync(`${bin("vite")} build --config ${viteConfig} --outDir dist/static`);
556
+ runSync(`${bin("vite")} build --config ${viteConfig} --ssr src/entry-server.tsx --outDir dist/server`);
553
557
  } else {
554
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --outDir dist/static --mode ${opts.mode}`);
555
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --ssr src/entry-server.tsx --outDir dist/server --mode ${opts.mode}`);
558
+ runSync(`${bin("vite")} build --config ${viteConfig} --outDir dist/static --mode ${opts.mode}`);
559
+ runSync(`${bin("vite")} build --config ${viteConfig} --ssr src/entry-server.tsx --outDir dist/server --mode ${opts.mode}`);
556
560
  }
557
- runSync(`${bin("tsx")} ${pkg("prerender.ts")} --add-hash --mode ${opts.mode}`);
561
+ runSync(`node ${pkg("prerender.js")} --add-hash --mode ${opts.mode}`);
558
562
  });
559
563
  program.command("eshn").description("Generate with --mode eshn").action(async () => {
560
- runSync(`${bin("tsx")} ${pkg("states.ts")}`);
561
- runSync(`${bin("tsx")} ${pkg("styles.ts")}`);
562
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --outDir dist/static --mode eshn`);
563
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --ssr src/entry-server.tsx --outDir dist/server --mode eshn`);
564
- runSync(`${bin("tsx")} ${pkg("prerender.ts")} --add-hash --mode eshn`);
564
+ const viteConfig = path.resolve(packageDir, "..", "vite.config.ts");
565
+ runSync(`node ${pkg("states.js")}`);
566
+ runSync(`node ${pkg("styles.js")}`);
567
+ runSync(`${bin("vite")} build --config ${viteConfig} --outDir dist/static --mode eshn`);
568
+ runSync(`${bin("vite")} build --config ${viteConfig} --ssr src/entry-server.tsx --outDir dist/server --mode eshn`);
569
+ runSync(`node ${pkg("prerender.js")} --add-hash --mode eshn`);
565
570
  });
566
571
  program.command("inte").description("Build and integrate with backend (styles + build + prerender + integration)").action(async () => {
567
- runSync(`${bin("tsx")} ${pkg("styles.ts")}`);
568
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --outDir dist/static`);
569
- runSync(`${bin("vite")} build --config ${pkg("vite.config.ts")} --ssr src/entry-server.tsx --outDir dist/server`);
570
- runSync(`${bin("tsx")} ${pkg("prerender.ts")}`);
571
- runSync(`${bin("tsx")} ${pkg("integration.ts")}`);
572
+ const viteConfig = path.resolve(packageDir, "..", "vite.config.ts");
573
+ runSync(`node ${pkg("styles.js")}`);
574
+ runSync(`${bin("vite")} build --config ${viteConfig} --outDir dist/static`);
575
+ runSync(`${bin("vite")} build --config ${viteConfig} --ssr src/entry-server.tsx --outDir dist/server`);
576
+ runSync(`node ${pkg("prerender.js")}`);
577
+ runSync(`node ${pkg("integration.js")}`);
572
578
  });
573
579
  program.command("styles").description("Compile SCSS").option("--watch", "Watch for changes").action(async (opts) => {
574
- const args = [pkg("styles.ts")];
580
+ const args = [pkg("styles.js")];
575
581
  if (opts.watch) args.push("--watch");
576
- await run(bin("tsx"), args);
582
+ await run("node", args);
577
583
  });
578
584
  program.command("prerender").description("Pre-render HTML files").option("--add-hash", "Add content hashes to asset URLs").option("--mode <mode>", "build mode", "production").action(async (opts) => {
579
- const args = [pkg("prerender.ts")];
585
+ const args = [pkg("prerender.js")];
580
586
  if (opts.addHash) args.push("--add-hash");
581
587
  args.push("--mode", opts.mode);
582
- await run(bin("tsx"), args);
588
+ await run("node", args);
583
589
  });
584
590
  program.parseAsync(process.argv).catch(async (error) => {
585
591
  console.log(red(error));
@@ -1,179 +1,130 @@
1
- /* eslint-disable no-console */
2
- import fs from 'fs';
3
- import path, { resolve } from 'path';
4
- import crypto from 'node:crypto';
5
- import nodeFs from 'node:fs';
6
-
7
- import slash from 'slash';
8
- import { glob } from 'glob';
9
- import { loadEnv } from 'vite';
10
- import chalk from 'chalk';
11
-
12
- interface CopyItem {
13
- from: string;
14
- to?: string;
15
- }
16
-
17
- interface FileExistCheck {
18
- folder?: string;
19
- fileName: string | RegExp;
20
- }
21
-
22
- const argvModeIndex = process.argv.indexOf('--mode');
23
- const mode =
24
- argvModeIndex >= 0 && argvModeIndex < process.argv.length - 1 && !process.argv[argvModeIndex + 1].startsWith('-')
25
- ? process.argv[argvModeIndex + 1]
26
- : 'production';
1
+ import fs from "fs";
2
+ import path, { resolve } from "path";
3
+ import crypto from "node:crypto";
4
+ import fs$1 from "node:fs";
5
+ import slash from "slash";
6
+ import { glob } from "glob";
7
+ import { loadEnv } from "vite";
8
+ import chalk from "chalk";
9
+ const argvModeIndex = process.argv.indexOf("--mode");
10
+ const mode = argvModeIndex >= 0 && argvModeIndex < process.argv.length - 1 && !process.argv[argvModeIndex + 1].startsWith("-") ? process.argv[argvModeIndex + 1] : "production";
27
11
  const projectRoot = process.cwd();
28
12
  const xpackEnv = loadEnv(mode, projectRoot);
29
- const toAbsolute = (p: string) => slash(path.resolve(projectRoot, p));
13
+ const toAbsolute = (p) => slash(path.resolve(projectRoot, p));
30
14
  const log = console.log.bind(console);
31
-
32
- const hashes: Map<string, string> = new Map();
33
- const staticBasePath = toAbsolute('dist/static');
34
- const srcBasePath = toAbsolute('dist/static/assets');
15
+ const hashes = /* @__PURE__ */ new Map();
16
+ const staticBasePath = toAbsolute("dist/static");
17
+ const srcBasePath = toAbsolute("dist/static/assets");
35
18
  const destBasePath = toAbsolute(xpackEnv.VITE_INTE_ASSET_DIR);
36
- const patternPath = xpackEnv.VITE_INTE_PATTERN_DIR ? toAbsolute(xpackEnv.VITE_INTE_PATTERN_DIR) : undefined;
37
-
19
+ const patternPath = xpackEnv.VITE_INTE_PATTERN_DIR ? toAbsolute(xpackEnv.VITE_INTE_PATTERN_DIR) : void 0;
38
20
  if (patternPath && fs.existsSync(patternPath)) {
39
21
  fs.rmSync(patternPath, { recursive: true, force: true });
40
-
41
22
  fs.mkdirSync(patternPath, { recursive: true });
42
23
  }
43
-
44
- const copyItems: CopyItem[] = [
45
- { from: 'css' },
46
- { from: 'fonts' },
47
- { from: 'images' },
48
- { from: 'js' },
49
- { from: 'vendors' },
50
- { from: 'hashes.json' },
51
- { from: 'pages', to: patternPath },
24
+ const copyItems = [
25
+ { from: "css" },
26
+ { from: "fonts" },
27
+ { from: "images" },
28
+ { from: "js" },
29
+ { from: "vendors" },
30
+ { from: "hashes.json" },
31
+ { from: "pages", to: patternPath }
52
32
  ];
53
- const hashItems: string[] = ['css', 'images', 'js'];
54
-
33
+ const hashItems = ["css", "images", "js"];
55
34
  copyItems.forEach((item) => {
56
35
  const srcPath = slash(path.join(srcBasePath, item.from));
57
36
  const destPath = slash(item.to ?? path.join(destBasePath, item.from));
58
-
59
37
  if (!fs.existsSync(srcPath)) {
60
38
  return;
61
39
  }
62
-
63
40
  log(`Copy file ${srcPath} to ${destPath}`);
64
-
65
41
  if (fs.statSync(srcPath).isDirectory()) {
66
42
  if (fs.existsSync(destPath)) {
67
43
  fs.rmSync(destPath, { recursive: true, force: true });
68
44
  }
69
-
70
45
  fs.mkdirSync(destPath, { recursive: true });
71
-
72
46
  fs.cpSync(srcPath, destPath, { recursive: true, force: true });
73
47
  } else {
74
48
  const destDirPath = path.dirname(destPath);
75
-
76
49
  if (!fs.existsSync(destDirPath)) {
77
50
  fs.mkdirSync(destDirPath);
78
51
  }
79
-
80
52
  fs.copyFileSync(srcPath, destPath);
81
53
  }
82
54
  });
83
-
84
55
  hashItems.forEach((item) => {
85
56
  const srcPath = slash(path.join(srcBasePath, item));
86
- const files = glob.sync(srcPath + '/**/*.{css,js,svg}');
87
-
57
+ const files = glob.sync(srcPath + "/**/*.{css,js,svg}");
88
58
  files.forEach((file) => {
89
59
  const relativePath = slash(file.substring(staticBasePath.length));
90
-
91
60
  if (!/\.0x[a-z0-9_-]{8,12}\.\w+$/gi.test(file)) {
92
61
  const content = fs.readFileSync(file);
93
- const sha1Hash = crypto.createHash('sha1');
94
-
62
+ const sha1Hash = crypto.createHash("sha1");
95
63
  sha1Hash.update(content);
96
- const hash = sha1Hash.digest('base64url').substring(0, 10);
97
-
64
+ const hash = sha1Hash.digest("base64url").substring(0, 10);
98
65
  hashes.set(relativePath, hash);
99
66
  } else {
100
- hashes.set(relativePath, '');
67
+ hashes.set(relativePath, "");
101
68
  }
102
69
  });
103
70
  });
104
-
105
- const sortedHashes = Array.from(hashes)
106
- .sort((a, b) => a[0].localeCompare(b[0]))
107
- .reduce(
108
- (obj, [key, value]) => {
109
- obj[key] = value;
110
-
111
- return obj;
112
- },
113
- {} as { [key: string]: string }
114
- );
115
-
116
- fs.writeFileSync(path.join(destBasePath, 'hashes.json'), JSON.stringify(sortedHashes, null, ' '));
117
-
71
+ const sortedHashes = Array.from(hashes).sort((a, b) => a[0].localeCompare(b[0])).reduce(
72
+ (obj, [key, value]) => {
73
+ obj[key] = value;
74
+ return obj;
75
+ },
76
+ {}
77
+ );
78
+ fs.writeFileSync(path.join(destBasePath, "hashes.json"), JSON.stringify(sortedHashes, null, " "));
118
79
  if (patternPath) {
119
80
  fs.mkdirSync(patternPath, { recursive: true });
120
- glob.sync('./dist/static/{atoms,molecules,organisms,templates,pages}/**/*.*').forEach((p) => {
121
- let basename = '';
122
- const segments = slash(p).split('/');
123
-
81
+ glob.sync("./dist/static/{atoms,molecules,organisms,templates,pages}/**/*.*").forEach((p) => {
82
+ let basename = "";
83
+ const segments = slash(p).split("/");
124
84
  if (segments.length < 4) return;
125
85
  switch (segments.length) {
126
86
  case 4:
127
- basename = path.basename(slash(p).replaceAll(/(atoms|molecules|organisms|templates|pages)\/([\w._-]+)$/gi, '$1-$2'));
87
+ basename = path.basename(slash(p).replaceAll(/(atoms|molecules|organisms|templates|pages)\/([\w._-]+)$/gi, "$1-$2"));
128
88
  fs.copyFileSync(p, resolve(patternPath, basename));
129
89
  break;
130
90
  default:
131
91
  segments.splice(0, 2);
132
- nodeFs.cpSync(p, resolve(patternPath, segments.join('-')), { recursive: true });
92
+ fs$1.cpSync(p, resolve(patternPath, segments.join("-")), { recursive: true });
133
93
  break;
134
94
  }
135
95
  });
136
-
137
- glob.sync(slash(path.resolve(patternPath + '/**/*.{htm,html}'))).forEach((p) => {
138
- const text = fs.readFileSync(p, 'utf-8');
139
- const newText = text
140
- .replaceAll(/react-loader\.0x[a-z0-9_-]{8,12}\.js/gi, 'react-loader.0x00000000.js')
141
- .replaceAll(/\.svg\?v=[a-z0-9_-]+/gi, '.svg');
142
-
96
+ glob.sync(slash(path.resolve(patternPath + "/**/*.{htm,html}"))).forEach((p) => {
97
+ const text = fs.readFileSync(p, "utf-8");
98
+ const newText = text.replaceAll(/react-loader\.0x[a-z0-9_-]{8,12}\.js/gi, "react-loader.0x00000000.js").replaceAll(/\.svg\?v=[a-z0-9_-]+/gi, ".svg");
143
99
  if (text !== newText) {
144
100
  fs.writeFileSync(p, newText);
145
101
  }
146
102
  });
147
103
  }
148
-
149
- const checkExistFileList: FileExistCheck[] = [
150
- { fileName: 'hashes.json' },
151
- { fileName: /react-loader\.0x[a-z0-9_-]{8,12}\.js/gi, folder: 'js' },
152
- { fileName: 'main.js', folder: 'js' },
104
+ const checkExistFileList = [
105
+ { fileName: "hashes.json" },
106
+ { fileName: /react-loader\.0x[a-z0-9_-]{8,12}\.js/gi, folder: "js" },
107
+ { fileName: "main.js", folder: "js" }
153
108
  ];
154
109
  let isAllExist = true;
155
-
156
110
  checkExistFileList.forEach((file) => {
157
- if (typeof file.fileName === 'string') {
158
- const destPath = slash(path.join(destBasePath, file.folder ?? '', file.fileName.toString()));
159
-
111
+ if (typeof file.fileName === "string") {
112
+ const destPath = slash(path.join(destBasePath, file.folder ?? "", file.fileName.toString()));
160
113
  if (!fs.existsSync(destPath)) {
161
114
  log(chalk.yellow(`Cannot find: ${destPath}`));
162
115
  isAllExist = false;
163
116
  }
164
117
  } else {
165
118
  const fileName = file.fileName;
166
- const folderFiles = slash(path.join(destBasePath, file.folder ?? ''));
119
+ const folderFiles = slash(path.join(destBasePath, file.folder ?? ""));
167
120
  const files = fs.readdirSync(folderFiles);
168
121
  const found = files.find((f) => fileName.test(f));
169
-
170
122
  if (!found) {
171
123
  log(chalk.yellow(`Cannot find: ${slash(path.join(folderFiles, fileName.toString()))}`));
172
124
  isAllExist = false;
173
125
  }
174
126
  }
175
127
  });
176
-
177
128
  if (!isAllExist) {
178
129
  process.exit(1);
179
130
  }
@@ -0,0 +1,33 @@
1
+ import { execSync } from "child_process";
2
+ import { glob } from "glob";
3
+ const migration = async () => {
4
+ const usableFiles = ["./xpack/styles/root.scss"];
5
+ const forwardableFiles = [
6
+ "./src/assets/styles/style-base.scss",
7
+ "./src/assets/styles/style.all.scss",
8
+ "./src/assets/styles/00-abstracts/_abstracts.scss",
9
+ "./src/assets/styles/01-mixins/_mixins.scss",
10
+ "./src/assets/styles/02-base/_base.scss"
11
+ ];
12
+ for (const file of forwardableFiles) {
13
+ try {
14
+ console.log(`Migrating ${file}`);
15
+ execSync(`bunx sass-migrator --migrate-deps module --forward=all ${file}`, { stdio: "inherit" });
16
+ } catch (err) {
17
+ console.error(err.message);
18
+ }
19
+ }
20
+ const componentFiles = await glob(["./src/atoms/**/*.scss", "./src/molecules/**/*.scss", "./src/organisms/**/*.scss"], { nodir: true });
21
+ const allFiles = [...usableFiles, ...componentFiles];
22
+ for (const file of allFiles) {
23
+ try {
24
+ console.log(`Migrating ${file}`);
25
+ execSync(`bunx sass-migrator module --migrate-deps ${file}`, { stdio: "inherit" });
26
+ } catch (err) {
27
+ console.error(err.message);
28
+ }
29
+ }
30
+ };
31
+ migration().catch((err) => {
32
+ console.error("An error occurred during migration:", err.message);
33
+ });
@@ -0,0 +1,158 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { pathToFileURL } from "url";
4
+ import crypto from "node:crypto";
5
+ import jsBeautify from "js-beautify";
6
+ import * as cheerio from "cheerio";
7
+ import slash from "slash";
8
+ import _ from "lodash";
9
+ import { loadEnv } from "vite";
10
+ import chalk from "chalk";
11
+ const argvModeIndex = process.argv.indexOf("--mode");
12
+ const mode = argvModeIndex >= 0 && argvModeIndex < process.argv.length - 1 && !process.argv[argvModeIndex + 1].startsWith("-") ? process.argv[argvModeIndex + 1] : "production";
13
+ const projectRoot = process.cwd();
14
+ const xpackEnv = loadEnv(mode, projectRoot);
15
+ const toAbsolute = (p) => path.resolve(projectRoot, p);
16
+ const log = console.log.bind(console);
17
+ const template = fs.readFileSync(toAbsolute(process.env.VITE_TEMPLATE ?? "dist/static/index.html"), "utf-8");
18
+ const { render, routesToPrerender } = await import(pathToFileURL(toAbsolute("./dist/server/entry-server.js")).href);
19
+ const beautifyOptions = {
20
+ indent_size: 2,
21
+ indent_char: " ",
22
+ keep_array_indentation: false,
23
+ break_chained_methods: false,
24
+ indent_scripts: "normal",
25
+ brace_style: "collapse",
26
+ space_before_conditional: true,
27
+ unescape_strings: false,
28
+ jslint_happy: false,
29
+ end_with_newline: false,
30
+ wrap_line_length: 0,
31
+ indent_inner_html: false,
32
+ comma_first: false,
33
+ e4x: false,
34
+ indent_empty_lines: false,
35
+ wrap_attributes: "force",
36
+ max_preserve_newlines: 5,
37
+ preserve_newlines: true
38
+ };
39
+ const updateResourcePath = ($, tagName, attr, addHash) => {
40
+ $(tagName).each((_2, el) => {
41
+ const href = $(el).attr(attr);
42
+ if (href && href.startsWith("/")) {
43
+ let newPath = href;
44
+ if (process.env.VITE_DOMAIN) {
45
+ newPath = process.env.VITE_DOMAIN + newPath;
46
+ }
47
+ if (href.startsWith(xpackEnv.VITE_BASE_URL) && !href.startsWith(xpackEnv.VITE_BASE_URL + "assets/vendors/") && [".css", ".ico", ".js", ".webmanifest", ".svg"].includes(path.extname(href).toLowerCase()) && !/\.0x[a-z0-9]{8}\.\w+$/gi.test(href)) {
48
+ const path2 = toAbsolute("dist/static/" + href.substring(xpackEnv.VITE_BASE_URL.length));
49
+ if (fs.existsSync(path2)) {
50
+ const content = fs.readFileSync(path2);
51
+ const sha1Hash = crypto.createHash("sha1");
52
+ sha1Hash.update(content);
53
+ const hash = sha1Hash.digest("base64url").substring(0, 10);
54
+ if (addHash) {
55
+ newPath += "?v=" + hash;
56
+ }
57
+ } else if (path2.endsWith("mock-api.js")) ;
58
+ else {
59
+ log(chalk.yellow("Cannot find:", path2));
60
+ }
61
+ }
62
+ if (newPath != href) {
63
+ $(el).attr(attr, newPath);
64
+ }
65
+ }
66
+ });
67
+ };
68
+ const removeStyleBase = ($) => {
69
+ $('link[rel="stylesheet"]').each((_2, el) => {
70
+ const href = $(el).attr("href");
71
+ if (href?.includes("style-base")) {
72
+ $(el).remove();
73
+ }
74
+ });
75
+ };
76
+ const removeDuplicateAssets = ($, selector, attr, paths) => {
77
+ $(selector).each((_2, el) => {
78
+ if ($(el).attr("data-pl-inplace") === "true") {
79
+ return;
80
+ }
81
+ const path2 = $(el).attr(attr);
82
+ if (!path2) {
83
+ return;
84
+ }
85
+ const index = $(el).index();
86
+ const parent = $(el).parent().clone();
87
+ const child = parent.children()[index];
88
+ parent.empty();
89
+ parent.append(child);
90
+ const html = parent.html();
91
+ $(el).after("\n<!-- " + html + " -->");
92
+ if (paths.includes(path2)) {
93
+ $(el).remove();
94
+ return;
95
+ }
96
+ paths.push(path2);
97
+ $(el).removeAttr("data-pl-require");
98
+ if ($(el).attr("type") === "module") {
99
+ const deferValue = $(el).attr("defer");
100
+ if ($(el).attr("defer") === "" || deferValue === "defer" || deferValue === "true") {
101
+ $(el).removeAttr("defer");
102
+ }
103
+ }
104
+ $("head").append(el);
105
+ });
106
+ };
107
+ const viteAbsoluteUrl = (remain, addExtension = false) => {
108
+ const baseUrl = xpackEnv.VITE_BASE_URL;
109
+ const normalizedRemain = (remain?.startsWith("/") ? remain : "/" + remain) + (addExtension && !remain.endsWith("/") ? xpackEnv.VITE_PATH_EXTENSION ?? "" : "");
110
+ if (!baseUrl) {
111
+ return normalizedRemain;
112
+ }
113
+ if (!baseUrl.endsWith("/")) {
114
+ return baseUrl + normalizedRemain;
115
+ }
116
+ const len = baseUrl.length;
117
+ return baseUrl.substring(0, len - 1) + normalizedRemain;
118
+ };
119
+ const renderPage = async (renderedPages, addHash) => {
120
+ for (const route of routesToPrerender) {
121
+ const output = await render(viteAbsoluteUrl(route.route, true));
122
+ const destLocalizedFolderPath = toAbsolute("dist/static");
123
+ let html = template.replace("<!--app-html-->", output.html ?? "").replace("@style.scss", "/assets/css/" + route.name + ".css");
124
+ const $ = cheerio.load(html);
125
+ const paths = [];
126
+ removeDuplicateAssets($, "link[data-pl-require][href]", "href", paths);
127
+ removeDuplicateAssets($, "script[data-pl-require][src]", "src", paths);
128
+ updateResourcePath($, "link", "href", addHash);
129
+ updateResourcePath($, "script", "src", addHash);
130
+ updateResourcePath($, "img", "src", addHash);
131
+ if (route.route === "/") {
132
+ removeStyleBase($);
133
+ }
134
+ $("head title").text(route.name);
135
+ const fileName = (route.route === "/" ? "/index" : route.route) + ".html";
136
+ const filePath = `${destLocalizedFolderPath}${fileName}`;
137
+ if (!fs.existsSync(path.dirname(filePath))) {
138
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
139
+ }
140
+ html = $.html();
141
+ html = jsBeautify.html_beautify(html, beautifyOptions);
142
+ html = html.replace("/* app-styles */", output.styles);
143
+ fs.writeFileSync(toAbsolute(filePath), html);
144
+ log("pre-rendered:", slash(filePath));
145
+ renderedPages.push({
146
+ name: _.kebabCase(fileName.replaceAll(/\.\w+$/gi, "")),
147
+ url: `${process.env.VITE_DOMAIN ?? ""}${fileName}`,
148
+ fileName
149
+ });
150
+ }
151
+ };
152
+ (async () => {
153
+ const renderedPages = [];
154
+ const pool = [];
155
+ const addHash = !!process.argv.includes("--add-hash");
156
+ pool.push(renderPage(renderedPages, addHash));
157
+ await Promise.all(pool);
158
+ })();
@@ -0,0 +1,36 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import chokidar from "chokidar";
4
+ import { glob } from "glob";
5
+ import slash from "slash";
6
+ import { transformWithEsbuild } from "vite";
7
+ const log = console.log.bind(console);
8
+ const scriptCompile = async (inputPath) => {
9
+ console.log("compile:", slash(inputPath));
10
+ const code = fs.readFileSync(inputPath, "utf8");
11
+ return transformWithEsbuild(code, inputPath, {
12
+ minify: true,
13
+ format: "esm",
14
+ sourcemap: path.basename(inputPath).includes("critical") ? false : "external"
15
+ }).then((result) => {
16
+ const savePath = path.resolve("public/assets/js/" + path.parse(inputPath).name + ".js");
17
+ const saveDir = path.dirname(savePath);
18
+ if (!fs.existsSync(saveDir)) {
19
+ fs.mkdirSync(saveDir);
20
+ }
21
+ fs.writeFileSync(savePath, result.code);
22
+ }).catch((error) => {
23
+ log(error);
24
+ });
25
+ };
26
+ const run = async () => {
27
+ if (process.argv.includes("--watch")) {
28
+ const watcher = chokidar.watch("src/assets/scripts/**/*.{js,jsx,ts,tsx}");
29
+ watcher.on("add", scriptCompile).on("change", scriptCompile).on("unlink", (path2) => log(`File ${path2} has been removed`));
30
+ } else {
31
+ const pool = [];
32
+ glob.sync("src/assets/scripts/**/*.{js,jsx,ts,tsx}").forEach((p) => pool.push(scriptCompile(p)));
33
+ await Promise.all(pool);
34
+ }
35
+ };
36
+ await run();