onlybuild 1.0.0 → 1.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## [v1.1.0](https://github.com/neogeek/onlybuild/tree/v1.1.0) - (2024-04-26)
4
+
5
+ [Full Changelog](https://github.com/neogeek/onlybuild/compare/v1.0.0...v1.1.0)
6
+
7
+ - [feat] Added input arg and version, help and out flags. [#2](https://github.com/neogeek/onlybuild/pull/2)
8
+ - [feat] Broke out build and copy methods into smaller ones. [#1](https://github.com/neogeek/onlybuild/pull/1)
9
+
10
+ ## [v1.0.0](https://github.com/neogeek/onlybuild/tree/v1.0.0) - (2024-04-23)
11
+
12
+ - Initial release! 🎉
13
+
14
+ _This changelog was generated with **[generate-local-changelog](https://github.com/neogeek/generate-local-changelog)**_
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  [![Test](https://github.com/neogeek/onlybuild/actions/workflows/test.workflow.yml/badge.svg)](https://github.com/neogeek/onlybuild/actions/workflows/test.workflow.yml)
6
6
  [![Publish](https://github.com/neogeek/onlybuild/actions/workflows/publish.workflow.yml/badge.svg)](https://github.com/neogeek/onlybuild/actions/workflows/publish.workflow.yml)
7
+ [![Documentation](https://doxdox.org/images/badge-flat.svg)](https://doxdox.org/neogeek/onlybuild)
7
8
  [![NPM version](https://img.shields.io/npm/v/onlybuild)](https://www.npmjs.org/package/onlybuild)
8
9
  [![Join the chat at https://discord.gg/nNtFsfd](https://img.shields.io/badge/discord-join%20chat-7289DA.svg)](https://discord.gg/nNtFsfd)
9
10
 
@@ -26,11 +27,14 @@
26
27
  ## Table of Contents
27
28
 
28
29
  - [Install](#install)
30
+ - [Usage](#usage)
29
31
  - [Quick Start Guide](#quick-start-guide)
30
32
  - [Getting Started](#getting-started)
31
33
  - [File Structure](#file-structure)
32
34
  - [Ignore Files](#ignore-files)
33
35
  - [Formatting Files](#formatting-files)
36
+ - [Watching For Changes](#watching-for-changes)
37
+ - [Local Server](#local-server)
34
38
  - [Examples](#examples)
35
39
  - [Benchmark](#benchmark)
36
40
  - [Testing](#testing)
@@ -76,6 +80,19 @@ $ npm install onlybuild --save-dev
76
80
  $ npm run build
77
81
  ```
78
82
 
83
+ ## Usage
84
+
85
+ ```bash
86
+ Usage: onlybuild <path> [options]
87
+
88
+ Options:
89
+
90
+ -h, --help Display this help message.
91
+ -v, --version Display the current installed version.
92
+ -o, --out Sets build directory. Default path is build/
93
+ -i, --ignore Sets ignore file path. Default path is .onlyignore
94
+ ```
95
+
79
96
  ## Quick Start Guide
80
97
 
81
98
  Create a new file `index.mjs` with the following contents:
@@ -142,6 +159,31 @@ import { marked } from 'marked';
142
159
  export default marked.parse(await readFile('index.md', 'utf8'));
143
160
  ```
144
161
 
162
+ ### Parse Markdown w/ Syntax Highlighting
163
+
164
+ This Markdown example parses code blocks and adds CSS classes before rendering the page to HTML.
165
+
166
+ ```javascript
167
+ import { readFile } from 'node:fs/promises';
168
+
169
+ import { Marked } from 'marked';
170
+
171
+ import { markedHighlight } from 'marked-highlight';
172
+ import hljs from 'highlight.js';
173
+
174
+ const marked = new Marked(
175
+ markedHighlight({
176
+ langPrefix: 'hljs language-',
177
+ highlight(code, lang, info) {
178
+ const language = hljs.getLanguage(lang) ? lang : 'plaintext';
179
+ return hljs.highlight(code, { language }).value;
180
+ }
181
+ })
182
+ );
183
+
184
+ export default marked.parse(await readFile('index.md', 'utf8'));
185
+ ```
186
+
145
187
  ### <code>&#96;html&#96;</code> String Template Utility
146
188
 
147
189
  The `onlybuild` library includes an optional <code>&#96;html&#96;</code> string template utility that can be used to add syntax highlighting and formatting to HTML, making it easier to author HTML in JavaScript.
@@ -156,14 +198,62 @@ Install the [lit-html](https://marketplace.visualstudio.com/items?itemName=biern
156
198
 
157
199
  ## File Structure
158
200
 
159
- When you run `npx onlybuild` the default export of all `.mjs` file will be captured and written to files in a `build/` directory.
201
+ When you run `npx onlybuild`, all `.mjs` files with a `export default` that returns a string will be captured and written to the `build/` directory. All other files will be copied with the same file structure to the `build` directory unless included in the `.onlyignore` file or in a default ignored directory, indicated by a leading `_` character.
160
202
 
161
203
  If the name of your `.mjs` file is `index.mjs` the output will be saved to `index.html`, but if it's name is `something-else.mjs` the output will be saved to `something-else/index.mjs`.
162
204
 
205
+ See the example file structure below for a more comprehensive example that includes building files and copying static files.
206
+
207
+ <table>
208
+ <tr>
209
+ <th>
210
+ Files
211
+ </v>
212
+ <th>
213
+ Build Output
214
+ </th>
215
+ <tr>
216
+ <td>
217
+
218
+ ```
219
+ ├── _includes
220
+ │ └── head.mjs
221
+ ├── about
222
+ │ └── index.mjs
223
+ ├── blog
224
+ │ └── hello-world.mjs
225
+ ├── css
226
+ │ └── styles.css
227
+ ├── images
228
+ │ └── icon.png
229
+ └── index.mjs
230
+ ```
231
+
232
+ </td>
233
+ <td>
234
+
235
+ ```
236
+ ├── index.html
237
+ ├── css
238
+ │ └── styles.css
239
+ ├── images
240
+ │ └── icon.png
241
+ ├── about
242
+ │ └── index.html
243
+ └── blog
244
+ └── hello-world
245
+ └── index.html
246
+
247
+ ```
248
+
249
+ </td></tr></table>
250
+
163
251
  ## Ignore Files
164
252
 
165
253
  If you want to ignore files from being generated into static files or copied into the `build.` directory you can add them to an ignore file called `.onlyignore`, which has a syntax similar to [`.gitignore`](https://git-scm.com/docs/gitignore) files.
166
254
 
255
+ As stated in the previous section, any files in a directory with a leading `_` character will be automatically ignored. Example: `_includes` or `_data`.
256
+
167
257
  ```
168
258
  *.md
169
259
 
@@ -174,16 +264,60 @@ LICENSE
174
264
 
175
265
  ## Formatting Files
176
266
 
177
- Originally, [Prettier](https://prettier.io/) was included in the build step, but it caused the build time to balloon to 3x its current time. Because of this, it was removed and is recommended to run after the build step, or not at all if it's not needed.
267
+ If you want to reformat the HTML files in the build directory, you can use [Prettier](https://prettier.io/) after the build completes.
178
268
 
179
- ```bash
180
- $ npx prettier --write "build/**/*.html"
269
+ ```json
270
+ {
271
+ ...
272
+ "scripts": {
273
+ "build": "onlybuild",
274
+ "format": "npx prettier --write \"build/**/*.html\""
275
+ },
276
+ ...
277
+ }
181
278
  ```
182
279
 
183
280
  If your `build/` directory is in `.gitignore` (which it probably should be) you will need to ignore the `.gitignore` file by setting the `--ignore-path` flag to something else. The file you set it to doesn't need to exist.
184
281
 
185
- ```bash
186
- $ npx prettier --write --ignore-path .prettierignore "build/**/*.html"
282
+ ```json
283
+ {
284
+ ...
285
+ "scripts": {
286
+ "build": "onlybuild",
287
+ "format": "npx prettier --write --ignore-path .prettierignore \"build/**/*.html\""
288
+ },
289
+ ...
290
+ }
291
+ ```
292
+
293
+ ## Watching For Changes
294
+
295
+ If you want to automatically rebuild the project when files are updated you can use [nodemon](https://nodemon.io/).
296
+
297
+ ```json
298
+ {
299
+ ...
300
+ "scripts": {
301
+ "build": "onlybuild",
302
+ "watch": "npx nodemon --ext mjs,md,css --ignore ./build -x \"npm run build\""
303
+ },
304
+ ...
305
+ }
306
+ ```
307
+
308
+ ## Local Server
309
+
310
+ Serving the files once the build is complete is easy using the NPM package [http-server](https://github.com/http-party/http-server).
311
+
312
+ ```json
313
+ {
314
+ ...
315
+ "scripts": {
316
+ "build": "onlybuild",
317
+ "serve": "npx http-server build"
318
+ },
319
+ ...
320
+ }
187
321
  ```
188
322
 
189
323
  ## Examples
package/bin/index.js CHANGED
@@ -1,16 +1,60 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { readFile } from 'node:fs/promises';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
3
7
  import { globby } from 'globby';
4
8
 
9
+ import parseCmdArgs from 'parse-cmd-args';
10
+
5
11
  import { buildFiles } from '../src/build.js';
6
12
  import { copyFiles } from '../src/copy.js';
7
13
 
14
+ const args = parseCmdArgs(null, {
15
+ requireUserInput: false
16
+ });
17
+
18
+ if (args.flags['--version'] || args.flags['-v']) {
19
+ process.stdout.write(
20
+ `${
21
+ JSON.parse(
22
+ await readFile(
23
+ join(dirname(fileURLToPath(import.meta.url)), '../package.json'),
24
+ 'utf8'
25
+ )
26
+ ).version
27
+ }\n`
28
+ );
29
+ process.exit();
30
+ } else if (args.flags['--help'] || args.flags['-h']) {
31
+ process.stdout.write(`Usage: onlybuild <path> [options]
32
+
33
+ Options:
34
+
35
+ -h, --help Display this help message.
36
+ -v, --version Display the current installed version.
37
+ -o, --out Sets build directory. Default path is build/
38
+ -i, --ignore Sets ignore file path. Default path is .onlyignore
39
+ `);
40
+ process.exit();
41
+ }
42
+
43
+ const [buildDir = 'build/'] = [args.flags['--out'], args.flags['-o']]
44
+ .filter(flag => typeof flag === 'string')
45
+ .map(String);
46
+
47
+ const [ignoreFile = '.onlyignore'] = [args.flags['--ignore'], args.flags['-i']]
48
+ .filter(flag => typeof flag === 'string')
49
+ .map(String);
50
+
8
51
  await buildFiles(
9
- await globby(['**/*.mjs', '!_*/**/*', '!node_modules/', '!build/'], {
52
+ await globby(['**/*.mjs', '!_*/**/*', '!node_modules/', `!${buildDir}`], {
10
53
  gitignore: true,
11
- ignoreFiles: ['.onlyignore']
54
+ ignoreFiles: [ignoreFile],
55
+ cwd: args.inputs[0]
12
56
  }),
13
- 'build/'
57
+ buildDir
14
58
  );
15
59
 
16
60
  await copyFiles(
@@ -22,14 +66,15 @@ await copyFiles(
22
66
  '!package.json',
23
67
  '!package-lock.json',
24
68
  '!node_modules/',
25
- '!build/'
69
+ `!${buildDir}`
26
70
  ],
27
71
  {
28
72
  gitignore: true,
29
- ignoreFiles: ['.onlyignore']
73
+ ignoreFiles: [ignoreFile],
74
+ cwd: args.inputs[0]
30
75
  }
31
76
  ),
32
- 'build/'
77
+ buildDir
33
78
  );
34
79
 
35
80
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "onlybuild",
3
3
  "description": "A zero-config cli for building static websites.",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "engines": {
6
6
  "node": ">=20.x"
7
7
  },
@@ -12,7 +12,8 @@
12
12
  "main": "./src/index.js",
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
- "globby": "14.0.1"
15
+ "globby": "14.0.1",
16
+ "parse-cmd-args": "5.0.1"
16
17
  },
17
18
  "scripts": {
18
19
  "test": "node --test"
package/src/build.js CHANGED
@@ -2,26 +2,45 @@ import { writeFile, mkdir } from 'node:fs/promises';
2
2
  import { basename, dirname, join, resolve } from 'node:path';
3
3
 
4
4
  /**
5
- * @param {string[]} paths
5
+ * Write the file to the build directory while creating the directory, recursively, if it doesn't exist.
6
+ *
7
+ * @param {string} path
6
8
  * @param {string} buildDir
9
+ * @param {string} contents
7
10
  */
8
- export const buildFiles = async (paths, buildDir) => {
9
- await Promise.all(
10
- paths.map(async path => {
11
- const filename = basename(path, '.mjs');
11
+ export const writeFileAndMakeDir = async (path, buildDir, contents) => {
12
+ const filename = basename(path, '.mjs');
12
13
 
13
- const directory =
14
- filename === 'index'
15
- ? join(buildDir, dirname(path))
16
- : join(buildDir, dirname(path), filename);
14
+ const directory =
15
+ filename === 'index'
16
+ ? join(buildDir, dirname(path))
17
+ : join(buildDir, dirname(path), filename);
17
18
 
18
- const html = (await import(resolve(path))).default;
19
+ await mkdir(directory, { recursive: true });
20
+
21
+ await writeFile(join(directory, 'index.html'), contents);
22
+ };
23
+
24
+ /**
25
+ * Import the default export of a JavaScript file and check that the default export is a string before writing the contents to a build file.
26
+ *
27
+ * @param {string} path
28
+ * @param {string} buildDir
29
+ */
30
+ export const buildFile = async (path, buildDir) => {
31
+ const contents = (await import(resolve(path))).default;
19
32
 
20
- if (typeof html === 'string') {
21
- await mkdir(directory, { recursive: true });
33
+ if (typeof contents === 'string') {
34
+ await writeFileAndMakeDir(path, buildDir, contents);
35
+ }
36
+ };
22
37
 
23
- await writeFile(join(directory, `index.html`), html);
24
- }
25
- })
26
- );
38
+ /**
39
+ * Iterate over all the file paths and write them to the build directory.
40
+ *
41
+ * @param {string[]} paths
42
+ * @param {string} buildDir
43
+ */
44
+ export const buildFiles = async (paths, buildDir) => {
45
+ await Promise.all(paths.map(async path => await buildFile(path, buildDir)));
27
46
  };
package/src/copy.js CHANGED
@@ -2,15 +2,25 @@ import { copyFile, mkdir } from 'node:fs/promises';
2
2
  import { dirname, join } from 'node:path';
3
3
 
4
4
  /**
5
+ * Copy the file to the build directory while creating the directory, recursively, if it doesn't exist.
6
+ *
7
+ * @param {string} path
8
+ * @param {string} buildDir
9
+ */
10
+ export const copyFileAndMakeDir = async (path, buildDir) => {
11
+ await mkdir(join(buildDir, dirname(path)), { recursive: true });
12
+
13
+ await copyFile(path, join(buildDir, path));
14
+ };
15
+
16
+ /**
17
+ * Iterate over all the file paths and copy them to the build directory.
18
+ *
5
19
  * @param {string[]} paths
6
20
  * @param {string} buildDir
7
21
  */
8
22
  export const copyFiles = async (paths, buildDir) => {
9
23
  await Promise.all(
10
- paths.map(async path => {
11
- await mkdir(join(buildDir, dirname(path)), { recursive: true });
12
-
13
- await copyFile(path, join(buildDir, path));
14
- })
24
+ paths.map(async path => await copyFileAndMakeDir(path, buildDir))
15
25
  );
16
26
  };
package/src/html.js CHANGED
@@ -1,4 +1,6 @@
1
1
  /**
2
+ * String template utility that adds syntax highlighting and formatting in text editors.
3
+ *
2
4
  * @param {TemplateStringsArray} strings
3
5
  * @param {any[]} values
4
6
  */