host-mdx 2.2.0 → 2.3.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 CHANGED
@@ -5,47 +5,71 @@ A cli tool to create and serve a static html website from a given mdx directory
5
5
 
6
6
  ## 🛠️ Usage
7
7
 
8
+ ### With npx:
9
+ ```bash
10
+ npx host-mdx --input-path="path/to/input" --output-path="path/to/output"
11
+ ```
12
+
13
+ List of all available options:
8
14
  ```
9
- host-mdx [options]
15
+ Usage: host-mdx [options]
10
16
 
11
17
  Options:
12
- --create-only, -c Only create the html website from mdx does not host
13
- --help, -h Shows all available options
14
- --input-path=... The path at which all mdx files are stored
15
- --output-path=... The path to which all html files will be generated
16
- --port=... Localhost port number on which to host
17
- --track-changes, -t Tracks any changes made & auto reloads
18
- --verobse, -v Shows additional log messages
18
+ --concurrency=<num> Limit number of files to concurrently process (Optional, default: 1)
19
+ --create-only, -c Only creates the html website from mdx does not host
20
+ --help, -h Shows all available options
21
+ --input-path=<path> The path at which all mdx files are stored
22
+ --output-path=<path> The path to which all html files will be generated
23
+ --port=<num> Localhost port number on which to host
24
+ --track-changes, -t Tracks any changes & auto reloads, -t=hard for hard reload
25
+ --verbose, -v Shows additional log messages
19
26
  ```
20
27
 
21
28
  > If `--input-path` is not provided it will default to `./` i.e. current working directory\
22
29
  > If `--output-path` is not provided a temp folder will be created automatically & deleted upon exit
23
30
 
24
- You can add a file by the name `.hostmdxignore` at the root of your project to filter out which files/folders to skip while generating html
25
- (similar to [.gitignore](https://git-scm.com/docs/gitignore))
26
31
 
27
- You can also add a file by the name `host-mdx.js` at the root of your input folder as a config file with access to the following:
32
+
33
+ ### With import/require:
28
34
 
29
35
  ```js
30
- onSiteCreateStart(inputPath, outputPath)
31
- onSiteCreateEnd(inputPath, outputPath, wasInterrupted)
32
- onFileCreateStart(inputPath, outputPath, inFilePath, outFilePath)
33
- onFileCreateEnd(inputPath, outputPath, inFilePath, outFilePath, result)
34
- modBundleMDXSettings(inputPath, outputPath, settings)
35
- modGlobalArgs(inputPath, outputPath, globalArgs)
36
- toTriggerRecreate(event, path)
36
+ import { HostMdx } from "host-mdx";
37
+ // const { HostMdx } = require("host-mdx");
38
+
39
+ const inputPath = "/home/mrm/Desktop/website-mdx"
40
+ const outputPath = "/home/mrm/Desktop/website-html"
41
+ const configs = {
42
+ toBeVerbose: true,
43
+ port:3000,
44
+ trackChanges:1
45
+ }
46
+ const hostMdx = new HostMdx(inputPath, outputPath, configs);
47
+ hostMdx.start();
37
48
  ```
38
49
 
39
- > **Note:** Any changes made to `host-mdx.js` or any new package added requires complete restart otherwise changes will not reflect due to [this bug](https://github.com/nodejs/node/issues/49442)
40
50
 
41
- Default global variables you can use inside any .mdx files:
51
+ ### Additional:
52
+
53
+ You can add a file by the name `.hostmdxignore` at the root of your project to filter out which files/folders to skip while generating html
54
+ (similar to [.gitignore](https://git-scm.com/docs/gitignore))
55
+
56
+ You can also add a file by the name `host-mdx.js` at the root of your input folder as a config file (Look at the example below for all available options)
57
+
42
58
 
59
+ > **Note:**
60
+ > 1. Any config properties passed from npx or import e.g. `port`, `toBeVerbose`, `trackChanges`, etc will override `host-mdx.js` export values
61
+ > 1. Any changes made to `host-mdx.js` or any new package added requires complete restart otherwise changes will not reflect due to [this bug](https://github.com/nodejs/node/issues/49442)
62
+
63
+ <br/>
64
+
65
+ Default global variables you can use inside any .mdx files:
43
66
  ```
44
67
  hostmdxCwd
45
68
  hostmdxInputPath
46
69
  hostmdxOutputPath
47
70
  ```
48
71
 
72
+
49
73
  ## 📖 Example
50
74
 
51
75
  Command:
@@ -58,6 +82,7 @@ Input Directory:
58
82
 
59
83
  ```
60
84
  my-website-template/
85
+ ├─ 404.mdx
61
86
  ├─ index.mdx
62
87
  ├─ .hostmdxignore
63
88
  ├─ host-mdx.js
@@ -90,42 +115,68 @@ static/temp.jpg
90
115
  `host-mdx.js` file content:
91
116
 
92
117
  ```js
93
- export function onSiteCreateStart(inputPath, outputPath) {
94
- console.log("onSiteCreateStart", inputPath, outputPath)
118
+ export async function onHostStarting(inputPath, outputPath, port) {
119
+ console.log("onHostStarting");
95
120
  }
96
- export function onSiteCreateEnd(inputPath, outputPath, wasSuccessful) {
97
- console.log("onSiteCreateEnd", inputPath, outputPath, wasSuccessful)
121
+ export async function onHostStarted(inputPath, outputPath, port) {
122
+ console.log("onHostStarted");
98
123
  }
99
- export function onFileCreateStart(inputFilePath, outputFilePath) {
100
- console.log("onFileCreateStart", inputFilePath, outputFilePath)
124
+ export async function onHostEnded(inputPath, outputPath, port) {
125
+ console.log("onHostEnded");
101
126
  }
102
- export function onFileCreateEnd(inputFilePath, outputFilePath) {
103
- console.log("onFileCreateEnd", inputFilePath, outputFilePath)
127
+ export async function onSiteCreateStart(inputPath, outputPath) {
128
+ console.log("onSiteCreateStart");
104
129
  }
105
- export function onHostStart(port) {
106
- console.log("onHostStart", port)
130
+ export async function onSiteCreateEnd(inputPath, outputPath, wasInterrupted) {
131
+ console.log("onSiteCreateEnd");
107
132
  }
108
- export function onHostEnd(port) {
109
- console.log("onHostEnd", port)
133
+ export async function onFileCreateStart(inputFilePath, outputFilePath, inFilePath, outFilePath) {
134
+ console.log("onFileCreateStart");
110
135
  }
111
- export function modBundleMDXSettings(inputPath, outputPath, settings) {
112
- // Modify settings ...
113
- return settings
136
+ export async function onFileCreateEnd(inputFilePath, outputFilePath, inFilePath, outFilePath, result) {
137
+ // `result = undefined` if file is not .mdx
138
+ // `result.html` contains stringified HTML
139
+ // `result.exports` contains exports from mdx
140
+ console.log("onFileCreateEnd");
114
141
  }
115
- export function toTriggerRecreate(event, path) {
142
+ export async function toIgnore(inputPath, outputPath, path) {
116
143
  const isGOutputStream = /\.goutputstream-\w+$/.test(path);
117
144
  if (isGOutputStream) {
118
- return false;
145
+ return true;
119
146
  }
120
147
 
121
- return true;
148
+ return false;
149
+ }
150
+ export async function modMDXCode(inputPath, outputPath, inFilePath, outFilePath, code){
151
+ // Modify code ...
152
+ return code;
153
+ }
154
+ export async function modGlobalArgs(inputPath, outputPath, globalArgs){
155
+ // Modify globalArgs ...
156
+ return globalArgs;
122
157
  }
158
+ export async function modBundleMDXSettings(inputPath, outputPath, settings) {
159
+ // Modify settings ...
160
+ return settings;
161
+ }
162
+ export async function modRebuildPaths(inputPath, outputPath, rebuildPaths) {
163
+ // Modify rebuildPaths ...
164
+ return rebuildPaths;
165
+ }
166
+ export const chokidarOptions = {
167
+ awaitWriteFinish: true
168
+ }
169
+ export const port = 3000;
170
+ export const trackChanges = 1; // 0=no-tracking, 1=soft-reload, 2=hard-reload
171
+ export const toBeVerbose = true;
172
+ export const concurrency = 10; // Lowest possible value: 1
123
173
  ```
124
174
 
125
175
  Output Directory:
126
176
 
127
177
  ```
128
178
  my-website/
179
+ ├─ 404.html
129
180
  ├─ index.html
130
181
  ├─ about/
131
182
  │ └─ index.html
@@ -141,6 +192,7 @@ my-website/
141
192
 
142
193
  The site will now be visible in the browser at `localhost:3113`
143
194
 
195
+
144
196
  ## 🔑 License
145
197
 
146
198
  MIT © [Manas Ravindra Makde](https://manasmakde.github.io/)
package/cli.js ADDED
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "path";
4
+ import * as readline from "readline";
5
+ import { HostMdx, createSite, TrackChanges, log } from "./index.js";
6
+
7
+
8
+ // Flags
9
+ const CONCURRENCY_FLAG = "--concurrency"
10
+ const CREATE_FLAG = "--create-only";
11
+ const CREATE_SHORT_FLAG = "-c";
12
+ const HELP_FLAG = "--help";
13
+ const HELP_SHORT_FLAG = "-h";
14
+ const INPUT_PATH_FLAG = "--input-path";
15
+ const OUTPUT_PATH_FLAG = "--output-path";
16
+ const PORT_FLAG = "--port";
17
+ const TRACK_CHANGES_FLAG = "--track-changes";
18
+ const TRACK_CHANGES_SHORT_FLAG = "-t";
19
+ const VERBOSE_FLAG = "--verbose";
20
+ const VERBOSE_SHORT_FLAG = "-v";
21
+
22
+
23
+ // Properties
24
+ const SOFT_RELOAD_ARG = "soft"
25
+ const HARD_RELOAD_ARG = "hard"
26
+ const HELP_MESSAGE = `Usage: host-mdx [options]
27
+
28
+ Options:
29
+ ${CONCURRENCY_FLAG}=<num> Limit number of files to concurrently process (Optional, default: 1)
30
+ ${CREATE_FLAG}, ${CREATE_SHORT_FLAG} Only creates the html website from mdx does not host
31
+ ${HELP_FLAG}, ${HELP_SHORT_FLAG} Shows all available options
32
+ ${INPUT_PATH_FLAG}=<path> The path at which all mdx files are stored
33
+ ${OUTPUT_PATH_FLAG}=<path> The path to which all html files will be generated
34
+ ${PORT_FLAG}=<num> Localhost port number on which to host
35
+ ${TRACK_CHANGES_FLAG}, ${TRACK_CHANGES_SHORT_FLAG} Tracks any changes & auto reloads, ${TRACK_CHANGES_SHORT_FLAG}=${HARD_RELOAD_ARG} for hard reload
36
+ ${VERBOSE_FLAG}, ${VERBOSE_SHORT_FLAG} Shows additional log messages
37
+ `;
38
+
39
+
40
+ // Utility Methods
41
+ function getInputPathFromArgs(rawArgs) {
42
+ let inputPath = rawArgs.find(val => val.startsWith(INPUT_PATH_FLAG));
43
+ let inputPathProvided = inputPath !== undefined;
44
+ inputPath = inputPathProvided ? inputPath.split('=')?.[1] : "";
45
+ return inputPath !== "" ? path.resolve(inputPath) : inputPath; // To ensure input path is absolute
46
+ }
47
+ function getOutputPathFromArgs(rawArgs) {
48
+ let outputPath = rawArgs.find(val => val.startsWith(OUTPUT_PATH_FLAG));
49
+ let outputPathProvided = outputPath !== undefined;
50
+ outputPath = outputPathProvided ? outputPath.split('=')?.[1] : "";
51
+ return outputPath !== "" ? path.resolve(outputPath) : outputPath; // To ensure input path is absolute
52
+ }
53
+ function getPortFromArgs(rawArgs) {
54
+ let port = rawArgs.find(val => val.startsWith(PORT_FLAG));
55
+ let portProvided = port !== undefined;
56
+ return portProvided ? Number(port.split('=')[1]) : undefined;
57
+ }
58
+ function getTrackChangesFromArgs(rawArgs) {
59
+ // If flag not passed do not track changes
60
+ let trackChanges = rawArgs.find(val => (val.startsWith(TRACK_CHANGES_FLAG) || val.startsWith(TRACK_CHANGES_SHORT_FLAG)));
61
+ if (trackChanges == undefined) {
62
+ return undefined;
63
+ }
64
+
65
+
66
+ // Check for argument passed (if any)
67
+ let trackChangesSplit = trackChanges?.split('=') ?? [];
68
+ let arg = trackChangesSplit?.[1];
69
+ if (arg === HARD_RELOAD_ARG) {
70
+ return TrackChanges.HARD;
71
+ }
72
+ else if (arg === SOFT_RELOAD_ARG) {
73
+ return TrackChanges.SOFT;
74
+ }
75
+
76
+
77
+ return TrackChanges.SOFT;
78
+ }
79
+ function getConcurrencyFromArgs(rawArgs) {
80
+ let concurrency = rawArgs.find(val => val.startsWith(CONCURRENCY_FLAG));
81
+ let concurrencyProvided = concurrency !== undefined;
82
+ return concurrencyProvided ? Number(concurrency.split('=')[1]) : undefined;
83
+ }
84
+ function listenForKey(reloadCallback, hardReloadCallback, exitCallback) {
85
+ readline.emitKeypressEvents(process.stdin);
86
+ process.stdin.setRawMode(true);
87
+ process.stdin.on("keypress", (chunk, key) => {
88
+ if (key && key.shift && key.name == 'r') {
89
+ hardReloadCallback();
90
+ }
91
+ else if (key && key.name == 'r') {
92
+ reloadCallback();
93
+ }
94
+ else if (key && key.sequence == '\x03') {
95
+ exitCallback();
96
+ }
97
+ });
98
+ }
99
+
100
+
101
+ // Main Methods
102
+ export async function main() {
103
+
104
+ // Get all arguments
105
+ const rawArgs = process.argv.slice(2);
106
+
107
+
108
+ // Help flag check, Print out help message & return if passed
109
+ if (rawArgs.includes(HELP_FLAG) || rawArgs.includes(HELP_SHORT_FLAG)) {
110
+ console.log(HELP_MESSAGE)
111
+ return;
112
+ }
113
+
114
+
115
+ // Assign input path
116
+ let inputPath = getInputPathFromArgs(rawArgs);
117
+
118
+
119
+ // Assign output path
120
+ let outputPath = getOutputPathFromArgs(rawArgs);
121
+
122
+
123
+ // Assign verbose
124
+ let toBeVerbose = rawArgs.includes(VERBOSE_FLAG) || rawArgs.includes(VERBOSE_SHORT_FLAG);
125
+
126
+
127
+ // Assign concurrency
128
+ let concurrency = getConcurrencyFromArgs(rawArgs);
129
+
130
+
131
+ // Assign to create only, Return if passed
132
+ let toCreateOnly = rawArgs.includes(CREATE_FLAG) || rawArgs.includes(CREATE_SHORT_FLAG);
133
+ if (toCreateOnly) {
134
+ try {
135
+ await createSite(inputPath, outputPath, null, undefined, { toBeVerbose });
136
+ }
137
+ catch (err) {
138
+ process.exitCode = 1; // Exit with error code if not created successfully
139
+ log(`Failed to create site!\n${err?.stack}`);
140
+ }
141
+
142
+ return;
143
+ }
144
+
145
+
146
+ // Assign port
147
+ let port = getPortFromArgs(rawArgs);
148
+
149
+
150
+ // Assign tracking changes
151
+ let trackChanges = getTrackChangesFromArgs(rawArgs);
152
+
153
+
154
+ // Start hosting
155
+ let configs = {
156
+ ...(port !== undefined && { port }),
157
+ ...(concurrency !== undefined && { concurrency }),
158
+ ...(trackChanges !== undefined && { trackChanges }),
159
+ ...(toBeVerbose && { toBeVerbose }),
160
+ }
161
+ let hostMdx = new HostMdx(inputPath, outputPath, configs);
162
+ let hasHostingStarted = await hostMdx.start();
163
+ if (!hasHostingStarted) {
164
+ return;
165
+ }
166
+
167
+
168
+ // Assign cleanup function
169
+ const cleanup = async () => {
170
+ process.stdin.setRawMode(false);
171
+ await hostMdx.stop();
172
+ process.exit(0); // Without this 'Ctrl + c' does not work DO NOT REMOVE
173
+ }
174
+
175
+
176
+ // Watch for key press
177
+ listenForKey(
178
+ async () => await hostMdx?.recreateSite(),
179
+ async () => await hostMdx?.recreateSite(true),
180
+ cleanup
181
+ );
182
+
183
+
184
+ // Watch for quit
185
+ process.on("exit", cleanup);
186
+ process.on("SIGINT", cleanup);
187
+ process.on("SIGTERM", cleanup);
188
+
189
+
190
+ // Log key press instructions
191
+ log(`(Press 'r' to reload, 'Shift + r' to hard reload, 'Ctrl+c' to exit)`);
192
+ }
193
+
194
+
195
+ main()