@portosaur/cli 0.1.5 → 0.2.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/bin/porto.mjs CHANGED
@@ -57,8 +57,9 @@ program
57
57
  .action(buildCommand);
58
58
 
59
59
  program
60
- .command("serve [siteDir]")
60
+ .command("serve [siteDir] [extraArgs...]")
61
61
  .description("Serve the built static site locally")
62
+ .allowUnknownOption()
62
63
  .action(serveCommand);
63
64
 
64
65
  program
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portosaur/cli",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for Portosaur - The static Personal portfolio site generator.",
5
5
  "license": "GPL-3.0-only",
6
6
  "author": "soymadip",
@@ -16,7 +16,7 @@
16
16
  ],
17
17
  "type": "module",
18
18
  "bin": {
19
- "porto": "./bin/porto.mjs"
19
+ "porto": "bin/porto.mjs"
20
20
  },
21
21
  "exports": {
22
22
  ".": {
@@ -26,9 +26,9 @@
26
26
  },
27
27
  "types": "./src/index.d.ts",
28
28
  "dependencies": {
29
- "@portosaur/core": "^0.1.5",
30
- "@portosaur/logger": "^0.1.5",
31
- "@portosaur/wizard": "^0.1.5",
29
+ "@portosaur/core": "^0.2.0",
30
+ "@portosaur/logger": "^0.2.0",
31
+ "@portosaur/wizard": "^0.2.0",
32
32
  "commander": "^13.1.0",
33
33
  "js-yaml": "^4.1.1"
34
34
  }
@@ -55,6 +55,7 @@ export async function buildCommand(siteDir, extraArgs = []) {
55
55
  siteTitle: userConfig.site?.title,
56
56
  siteTagline: userConfig.site?.tagline,
57
57
  staticDirs: ["static"],
58
+ portoAssetsDir: portoPaths.assets,
58
59
  });
59
60
 
60
61
  const configPath = writeConfigShim(UserRoot, portoPaths, {
@@ -41,9 +41,14 @@ export async function devCommand(siteDir, extraArgs = []) {
41
41
  const watcher = fs.watch(configYamlPath, (eventType) => {
42
42
  if (eventType === "change") {
43
43
  logger.info(`Detected change in ${configYaml}, reloading...`);
44
- // Touch the shim config to trigger Docusaurus reload
45
- const now = new Date();
46
- fs.utimesSync(configPath, now, now);
44
+
45
+ // Regenerate the static config shim with the updated values,
46
+ // which triggers Docusaurus' own file watcher to hot-reload.
47
+ try {
48
+ writeConfigShim(UserRoot, portoPaths);
49
+ } catch (err) {
50
+ logger.warn(`Failed to regenerate config: ${err.message}`);
51
+ }
47
52
  }
48
53
  });
49
54
 
@@ -384,9 +384,7 @@ export async function initCommand(options = {}) {
384
384
  // to the CLI package to avoid loose dev-mode predictions.
385
385
  const isTestProject = looksLikeTestProject(state.projectName);
386
386
 
387
- const portoVer = isTestProject
388
- ? "link:@portosaur/cli"
389
- : porto.version || "0.0.0";
387
+ const portoVer = isTestProject ? "*" : `^${porto.version || "0.0.0"}`;
390
388
 
391
389
  const templateVars = {
392
390
  projectName: state.projectName,
@@ -1,27 +1,42 @@
1
1
  import path from "path";
2
- import { runDocusaurus, validateProject } from "../utils/index.mjs";
2
+ import {
3
+ runDocusaurus,
4
+ validateProject,
5
+ Paths,
6
+ writeConfigShim,
7
+ } from "../utils/index.mjs";
3
8
  import { logger } from "@portosaur/logger";
4
9
 
5
10
  /**
6
11
  * Serves the built Portosaur site locally.
7
- *
8
- * Note: Docusaurus 'serve' doesn't require a config shim,
9
- * as it serves the already built static files from the output directory.
10
12
  */
11
13
  export async function serveCommand(siteDir, extraArgs = []) {
12
14
  const UserRoot = siteDir
13
15
  ? path.resolve(process.cwd(), siteDir)
14
16
  : process.cwd();
15
17
 
18
+ // Ensure extraArgs is always an array (in case options object is passed)
19
+ const argsArray = Array.isArray(extraArgs) ? extraArgs : [];
20
+
16
21
  // ------- Setup -------
17
22
 
18
23
  validateProject(UserRoot);
19
24
 
25
+ const portoPaths = {
26
+ root: Paths.root,
27
+ assets: path.join(Paths.theme, "assets"),
28
+ theme: path.join(Paths.theme, "theme"),
29
+ plugins: path.join(Paths.theme, "src/plugins"),
30
+ };
31
+
20
32
  try {
21
33
  logger.info("Serving built site...");
22
34
 
35
+ // Generate config shim so Docusaurus can locate site configuration
36
+ const configPath = writeConfigShim(UserRoot, portoPaths);
37
+
23
38
  // Docusaurus serve looks for the 'build' directory by default.
24
- await runDocusaurus("serve", UserRoot, "", extraArgs);
39
+ await runDocusaurus("serve", UserRoot, configPath, argsArray);
25
40
  } catch (error) {
26
41
  logger.error(`Failed to serve site: ${error.message}`);
27
42
  process.exit(1);
package/src/index.d.ts CHANGED
@@ -41,7 +41,7 @@ export function buildCommand(siteDir?: string, extraArgs?: string[]): void;
41
41
  /**
42
42
  * Serves the built static site locally.
43
43
  */
44
- export function serveCommand(siteDir?: string): void;
44
+ export function serveCommand(siteDir?: string, extraArgs?: string[]): void;
45
45
 
46
46
  /**
47
47
  * Generates the config schema.
@@ -8,8 +8,8 @@ site:
8
8
  title: "{{fullName}}"
9
9
  tagline: "Short description about you, your passion, your goals etc."
10
10
 
11
- favicon: "{{portoRoot}}/src/assets/img/svg/icon.svg"
12
- social_card: "{{portoRoot}}/src/assets/img/social-card.jpeg"
11
+ favicon: "{{portoRoot}}/assets/img/svg/icon.svg"
12
+ social_card: "{{portoRoot}}/assets/img/social-card.jpeg"
13
13
 
14
14
  # Auto set if deploying in Github/GitLab Pages
15
15
  url: "auto"
@@ -55,7 +55,7 @@ home_page:
55
55
  - "skill 1"
56
56
  - "skill 2"
57
57
  - "skill 3"
58
- resume: "{{portoRoot}}/src/assets/sample-resume.pdf"
58
+ resume: "{{portoRoot}}/assets/sample-resume.pdf"
59
59
 
60
60
  project_shelf:
61
61
  enable: true
@@ -69,7 +69,7 @@ home_page:
69
69
  repo: "https://github.com/yourname/project1"
70
70
 
71
71
  - title: "Your Awesome Project 2"
72
- icon: "{{portoRoot}}/src/assets/img/svg/icon.svg"
72
+ icon: "{{portoRoot}}/assets/img/svg/icon.svg"
73
73
  bg: "#5c8f2d"
74
74
  tags: ["tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7"]
75
75
  featured: true
@@ -9,7 +9,7 @@
9
9
  "serve": "porto serve"
10
10
  },
11
11
  "dependencies": {
12
- "@portosaur/cli": "^{{portoVer}}",
13
- "@portosaur/theme": "^{{portoVer}}"
12
+ "@portosaur/cli": "{{portoVer}}",
13
+ "@portosaur/theme": "{{portoVer}}"
14
14
  }
15
15
  }
@@ -1,6 +1,10 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
+ import { createRequire } from "node:module";
5
+
6
+ const require = createRequire(import.meta.url);
7
+
4
8
  const srcDir = path.resolve(import.meta.dirname, "../");
5
9
  const pkgDir = path.resolve(srcDir, "../");
6
10
 
@@ -27,17 +31,20 @@ export const Paths = {
27
31
  packageJson: path.join(pkgDir, "package.json"),
28
32
 
29
33
  /** Absolute path to the core package. */
30
- core: path.resolve(pkgDir, "../core"),
34
+ get core() {
35
+ try {
36
+ return path.dirname(require.resolve("@portosaur/core/package.json"));
37
+ } catch {
38
+ return path.resolve(pkgDir, "../core");
39
+ }
40
+ },
31
41
 
32
42
  /** Absolute path to the theme package. */
33
43
  get theme() {
34
- const localNodeModulesTheme = path.resolve(
35
- process.cwd(),
36
- "node_modules/@portosaur/theme",
37
- );
38
- if (fs.existsSync(localNodeModulesTheme)) {
39
- return localNodeModulesTheme;
44
+ try {
45
+ return path.dirname(require.resolve("@portosaur/theme/package.json"));
46
+ } catch {
47
+ return path.resolve(pkgDir, "../theme");
40
48
  }
41
- return path.resolve(pkgDir, "../theme");
42
49
  },
43
50
  };
@@ -1,13 +1,18 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { spawn } from "child_process";
4
+ import { createRequire } from "module";
5
+ import { loadUserConfig, buildDocuConfig } from "@portosaur/core";
4
6
 
5
7
  /**
6
- * Generates a Docusaurus config shim that loads Portosaur logic.
8
+ * Generates a static Docusaurus config file by evaluating the Portosaur config
9
+ * at CLI time and serializing the result. This avoids importing @portosaur/core
10
+ * inside Docusaurus' own build/serve runtime.
11
+ *
7
12
  * @param {string} UserRoot - The user's project directory.
8
- * @param {Object} portoPaths - Paths to Portosaur assets and core.
13
+ * @param {Object} portoPaths - Paths to Portosaur assets and theme.
9
14
  * @param {Object} [context={}] - Additional context for config generation.
10
- * @returns {string} The path to the generated shim file.
15
+ * @returns {string} The path to the generated config file.
11
16
  */
12
17
  export function writeConfigShim(UserRoot, portoPaths, context = {}) {
13
18
  const dotDir = path.join(UserRoot, ".docusaurus", "portosaur");
@@ -16,35 +21,19 @@ export function writeConfigShim(UserRoot, portoPaths, context = {}) {
16
21
  fs.mkdirSync(dotDir, { recursive: true });
17
22
  }
18
23
 
19
- // Resolve config file
20
- const configYaml = ["config.yaml", "config.yml"].find((file) =>
21
- fs.existsSync(path.join(UserRoot, file)),
22
- );
23
- if (!configYaml) throw new Error("config.yml not found");
24
-
25
- const configYamlAbsolute = path
26
- .resolve(UserRoot, configYaml)
27
- .replace(/\\/g, "/");
28
-
29
- // Prepare shim template
30
- const shimContent = `// Auto-generated by portosaur
31
- import fs from "fs";
32
- import yaml from "js-yaml";
33
-
34
- export default async function getConfig() {
35
- const { buildDocuConfig } = await import("@portosaur/core");
36
- const yamlContent = fs.readFileSync("${configYamlAbsolute}", "utf8");
37
- const rawConf = yaml.load(yamlContent);
24
+ // Load the user's YAML config and evaluate the full Docusaurus config object now.
25
+ const rawConf = loadUserConfig(UserRoot);
38
26
 
39
- return buildDocuConfig(rawConf, "${UserRoot.replace(/\\/g, "/")}", {
40
- portoPaths: ${JSON.stringify(portoPaths)},
41
- portoRoot: "${path.resolve(portoPaths.root).replace(/\\/g, "/")}",
42
- ...${JSON.stringify(context)}
27
+ const docuConfig = buildDocuConfig(rawConf, UserRoot, {
28
+ portoPaths,
29
+ portoRoot: path.resolve(portoPaths.root),
30
+ ...context,
43
31
  });
44
- }
45
- `;
46
32
 
47
- // Write and return shim path
33
+ // Serialize the config as a static export so Docusaurus never needs to
34
+ // dynamically import @portosaur/core during its own build or serve run.
35
+ const shimContent = `// Auto-generated by portosaur — do not edit\nexport default ${JSON.stringify(docuConfig, null, 2)};\n`;
36
+
48
37
  const shimPath = path.join(dotDir, "docusaurus.config.js");
49
38
  fs.writeFileSync(shimPath, shimContent);
50
39
 
@@ -155,27 +144,60 @@ export async function runDocusaurus(
155
144
  configPath,
156
145
  extraArgs = [],
157
146
  ) {
158
- const args = [
159
- "run",
160
- "--bun",
161
- "docusaurus",
162
- command,
163
- UserRoot,
164
- "--config",
165
- configPath,
166
- ...extraArgs,
167
- ];
147
+ const isBun =
148
+ typeof process !== "undefined" &&
149
+ process.versions &&
150
+ process.versions.bun !== undefined;
151
+
152
+ let bin;
153
+ let args;
154
+
155
+ if (isBun) {
156
+ bin = "bun";
157
+ args = ["run", "--bun", "docusaurus", command, UserRoot];
158
+ } else {
159
+ bin = "node";
160
+ let docusaurusBin;
161
+ try {
162
+ const require = createRequire(import.meta.url);
163
+ docusaurusBin = require.resolve("docusaurus/bin/docusaurus.mjs", {
164
+ paths: [UserRoot],
165
+ });
166
+ } catch (e) {
167
+ docusaurusBin = path.join(
168
+ UserRoot,
169
+ "node_modules",
170
+ "docusaurus",
171
+ "bin",
172
+ "docusaurus.mjs",
173
+ );
174
+ }
175
+ args = [docusaurusBin, command, UserRoot];
176
+ }
177
+
178
+ if (configPath) {
179
+ args.push("--config", configPath);
180
+ }
181
+
182
+ args.push(...extraArgs);
168
183
 
169
184
  // Skip actual execution in test mode
170
185
  if (process.env.PORTO_TEST_MODE === "true") {
171
- console.log(`[TEST_MODE] Would run docusaurus ${command} in ${UserRoot}`);
186
+ console.log(
187
+ `[TEST_MODE] Would run docusaurus ${command} in ${UserRoot} using ${bin}`,
188
+ );
172
189
  return Promise.resolve();
173
190
  }
174
191
 
175
- const child = spawn("bun", args, {
192
+ const childEnv = { ...process.env, FORCE_COLOR: "true" };
193
+ if (command === "build") {
194
+ childEnv.CI = "true";
195
+ }
196
+
197
+ const child = spawn(bin, args, {
176
198
  stdio: "inherit",
177
199
  cwd: UserRoot,
178
- env: { ...process.env, FORCE_COLOR: "true" },
200
+ env: childEnv,
179
201
  });
180
202
 
181
203
  return new Promise((resolve, reject) => {
@@ -1,9 +0,0 @@
1
- ---
2
- hide_table_of_contents: true
3
- ---
4
-
5
- import NoteCards from "portosaur/src/theme/components/NoteIndex/index.js";
6
-
7
- # Notes
8
-
9
- <NoteCards />