onlybuild 1.0.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/CONTRIBUTING.md +25 -0
- package/LICENSE +21 -0
- package/README.md +239 -0
- package/bin/index.js +35 -0
- package/package.json +37 -0
- package/src/build.js +27 -0
- package/src/copy.js +16 -0
- package/src/html.js +14 -0
- package/src/index.js +1 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Reporting Issues
|
|
4
|
+
|
|
5
|
+
If you have found a bug in `onlybuild` please consider the following when submitting an issue:
|
|
6
|
+
|
|
7
|
+
- **Search existing [GitHub Issues](https://github.com/neogeek/onlybuild/issues)** - The bug you are experiencing might have already been reported or even fixed in an unreleased version of `onlybuild` so be sure to review both [open](https://github.com/neogeek/onlybuild/issues?state=open) and [closed](https://github.com/neogeek/onlybuild/issues?state=closed) issues.
|
|
8
|
+
- **Create a reproducible test case** - To make it easier for maintainers to validate the issue please include a [gist](https://gist.github.com/) containing files used to reproduce the issue.
|
|
9
|
+
- **Include relevant information** - Include clear steps to reproduce the issue.
|
|
10
|
+
|
|
11
|
+
## Pull Requests
|
|
12
|
+
|
|
13
|
+
Before submitting a pull request, be sure that the following requirements are met:
|
|
14
|
+
|
|
15
|
+
- Additional tests have been added to validate the changes.
|
|
16
|
+
- Relevant documentation has been added.
|
|
17
|
+
- The build passes.
|
|
18
|
+
|
|
19
|
+
## Code Style
|
|
20
|
+
|
|
21
|
+
Make sure to install and enable the [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin in VS Code.
|
|
22
|
+
|
|
23
|
+
## License
|
|
24
|
+
|
|
25
|
+
By contributing to `onlybuild` you agree that your contributions fall under the same license, [The MIT License (MIT)](./LICENSE).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Scott Doxey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# onlybuild
|
|
2
|
+
|
|
3
|
+
> A zero-config cli for building static websites.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/neogeek/onlybuild/actions/workflows/test.workflow.yml)
|
|
6
|
+
[](https://github.com/neogeek/onlybuild/actions/workflows/publish.workflow.yml)
|
|
7
|
+
[](https://www.npmjs.org/package/onlybuild)
|
|
8
|
+
[](https://discord.gg/nNtFsfd)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🪄 Can be used without installing it via `npx onlybuild`
|
|
13
|
+
- 🐣 Small footprint when installed
|
|
14
|
+
- ⏱️ Fast build times, [see benchmark data](#Benchmark)
|
|
15
|
+
- 🧰 Use with any framework or no framework at all
|
|
16
|
+
- 📦 Easily deploy built files to any static file service, ex: Google Cloud Bucket, AWS S3, GitHub Pages
|
|
17
|
+
- 📖 Easily import data from local JSON files or fetch remote API data
|
|
18
|
+
|
|
19
|
+
## Social
|
|
20
|
+
|
|
21
|
+
- Star [this repo on GitHub](https://github.com/neogeek/onlybuild) for updates
|
|
22
|
+
- Follow me on [Bluesky](https://bsky.app/profile/scottdoxey.com) or [Twitter](https://twitter.com/neogeek)
|
|
23
|
+
- Join the [Discord](https://discord.gg/nNtFsfd)
|
|
24
|
+
- Follow me on [GitHub](https://github.com/neogeek/)
|
|
25
|
+
|
|
26
|
+
## Table of Contents
|
|
27
|
+
|
|
28
|
+
- [Install](#install)
|
|
29
|
+
- [Quick Start Guide](#quick-start-guide)
|
|
30
|
+
- [Getting Started](#getting-started)
|
|
31
|
+
- [File Structure](#file-structure)
|
|
32
|
+
- [Ignore Files](#ignore-files)
|
|
33
|
+
- [Formatting Files](#formatting-files)
|
|
34
|
+
- [Examples](#examples)
|
|
35
|
+
- [Benchmark](#benchmark)
|
|
36
|
+
- [Testing](#testing)
|
|
37
|
+
- [Contributing](#contributing)
|
|
38
|
+
- [Community Roadmap](#community-roadmap)
|
|
39
|
+
- [License](#license)
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
### Globally
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
$ npm install onlybuild -g
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
$ onlybuild
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### NPX
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
$ npx onlybuild
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Local
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
$ npm install onlybuild --save-dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
...
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "onlybuild"
|
|
70
|
+
},
|
|
71
|
+
...
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
$ npm run build
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick Start Guide
|
|
80
|
+
|
|
81
|
+
Create a new file `index.mjs` with the following contents:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
export default '<h1>Hello, world!</h1>';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Run `npx onlybuild` from the directory the `index.mjs` file is in.
|
|
88
|
+
|
|
89
|
+
That's it! You will now have a `build/` directory with an `index.html` file in it.
|
|
90
|
+
|
|
91
|
+
## Getting Started
|
|
92
|
+
|
|
93
|
+
### Simple Example
|
|
94
|
+
|
|
95
|
+
You can have the default export return a string.
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
export default '<h1>Hello, world!</h1>';
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Method Example
|
|
102
|
+
|
|
103
|
+
You can have the default export generate a string at runtime via a method.
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
const renderPage = () => '<h1>Hello, world!</h1>';
|
|
107
|
+
|
|
108
|
+
export default renderPage();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Asynchronous Example
|
|
112
|
+
|
|
113
|
+
You can return asynchronously if you need to read a local file or call an external API.
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
import { readFile } from 'node:fs/promises';
|
|
117
|
+
|
|
118
|
+
const renderPage = async () => await readFile('index.html', 'utf8');
|
|
119
|
+
|
|
120
|
+
export default renderPage();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const comments = await fetch(
|
|
125
|
+
'https://jsonplaceholder.typicode.com/posts/1/comments'
|
|
126
|
+
).then(response => response.json());
|
|
127
|
+
|
|
128
|
+
export default `<div>${comments
|
|
129
|
+
.map(post => `<section><h2>${comments.name}</h2><p>${post.body}</section>`)
|
|
130
|
+
.join('\n')}</div>`;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Parse Markdown
|
|
134
|
+
|
|
135
|
+
You can run the contents through other libraries, for example, converting a Markdown file into HTML before returning it using libraries like [Marked](https://github.com/markedjs/marked).
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
import { readFile } from 'node:fs/promises';
|
|
139
|
+
|
|
140
|
+
import { marked } from 'marked';
|
|
141
|
+
|
|
142
|
+
export default marked.parse(await readFile('index.md', 'utf8'));
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### <code>`html`</code> String Template Utility
|
|
146
|
+
|
|
147
|
+
The `onlybuild` library includes an optional <code>`html`</code> string template utility that can be used to add syntax highlighting and formatting to HTML, making it easier to author HTML in JavaScript.
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
import { html } from 'onlybuild';
|
|
151
|
+
|
|
152
|
+
export default html`<h1>Hello, world!</h1>`;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Install the [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) plugin in VS Code to help format the HTML on save.
|
|
156
|
+
|
|
157
|
+
## File Structure
|
|
158
|
+
|
|
159
|
+
When you run `npx onlybuild` the default export of all `.mjs` file will be captured and written to files in a `build/` directory.
|
|
160
|
+
|
|
161
|
+
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
|
+
|
|
163
|
+
## Ignore Files
|
|
164
|
+
|
|
165
|
+
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
|
+
|
|
167
|
+
```
|
|
168
|
+
*.md
|
|
169
|
+
|
|
170
|
+
screenshot.png
|
|
171
|
+
|
|
172
|
+
LICENSE
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Formatting Files
|
|
176
|
+
|
|
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.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
$ npx prettier --write "build/**/*.html"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
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
|
+
|
|
185
|
+
```bash
|
|
186
|
+
$ npx prettier --write --ignore-path .prettierignore "build/**/*.html"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Examples
|
|
190
|
+
|
|
191
|
+
1. [Hello, world!](./examples/hello-world/) - A simple Hello, world example.
|
|
192
|
+
1. [Markdown](./examples/markdown/) - Get the contents of a local Markdown file and convert the contents to HTML.
|
|
193
|
+
1. [External API](./examples/external-api/) - Output data fetched from an external API.
|
|
194
|
+
1. [<code>`html`</code> String Template](./examples/html-string-template/) - Use the <code>`html`</code> string template utility to add syntax highlighting to HTML.
|
|
195
|
+
1. [Includes](./examples/includes/) - An example that uses reusable includes for building multiple pages.
|
|
196
|
+
|
|
197
|
+
## Benchmark
|
|
198
|
+
|
|
199
|
+
> [!NOTE]
|
|
200
|
+
> Each run (for onlybuild only) was repeated 5 times and the average time was selected. This result set was generated on a MacBook Air (M1, 2020), macOS Sonoma 14.4.1, 8 GB memory.
|
|
201
|
+
|
|
202
|
+
Times shown are in seconds. Lower is better.
|
|
203
|
+
|
|
204
|
+
| Markdown Files | 250 | 500 | 1000 | 2000 | 4000 |
|
|
205
|
+
| ---------------------------------------------- | -------: | -------: | -------: | -------: | -------: |
|
|
206
|
+
| onlybuild | `0.321` | `0.390` | `0.554` | `0.892` | `1.717` |
|
|
207
|
+
| [Hugo](https://gohugo.io/) v0.101.0 | `0.071` | `0.110` | `0.171` | `0.352` | `0.684` |
|
|
208
|
+
| [Eleventy](https://www.11ty.dev/) 1.0.1 | `0.584` | `0.683` | `0.914` | `1.250` | `1.938` |
|
|
209
|
+
| [Astro](https://astro.build/) 1.0.1 | `2.270` | `3.172` | `5.098` | `9.791` | `22.907` |
|
|
210
|
+
| [Gatsby](https://www.gatsbyjs.com/) 4.19.0-cli | `14.462` | `15.722` | `17.967` | `22.356` | `29.059` |
|
|
211
|
+
|
|
212
|
+
See more benchmark data at <https://www.zachleat.com/web/build-benchmark/>
|
|
213
|
+
|
|
214
|
+
To run the benchmarks locally you have to install `bc`. This can be done on macOS by using `brew install bc`.
|
|
215
|
+
|
|
216
|
+
Once you have `bc` installed, install NPM packages for the main repo, then navigate to the `tests/benchmarks` directory, install NPM packages there as well, and then run `./bin/run.sh` to start the benchmark tests.
|
|
217
|
+
|
|
218
|
+
## Testing
|
|
219
|
+
|
|
220
|
+
Run all tests via `npm test`.
|
|
221
|
+
|
|
222
|
+
- Tests are authored using the native [Node.js test runner](https://nodejs.org/api/test.html).
|
|
223
|
+
- Tests are run automatically via GitHub Actions on each new PR.
|
|
224
|
+
- For you add a new feature or fix a bug, please include the benchmark output in the PR along with your device stats.
|
|
225
|
+
|
|
226
|
+
## Contributing
|
|
227
|
+
|
|
228
|
+
Be sure to review the [Contributing Guidelines](./CONTRIBUTING.md) before logging an issue or making a pull request.
|
|
229
|
+
|
|
230
|
+
## Community Roadmap
|
|
231
|
+
|
|
232
|
+
The goal of this project is to keep the features it offers to a minimum, allowing you, the developer, to forge your own path. If you have feature requests or bugs, please create an issue and tag them with the appropriate tag. If an issue already exists, vote for it with 👍.
|
|
233
|
+
|
|
234
|
+
- [Feature Requests](https://github.com/neogeek/onlybuild/labels/enhancement)
|
|
235
|
+
- [Bugs](https://github.com/neogeek/onlybuild/labels/bug)
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
[The MIT License (MIT)](./LICENSE)
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { globby } from 'globby';
|
|
4
|
+
|
|
5
|
+
import { buildFiles } from '../src/build.js';
|
|
6
|
+
import { copyFiles } from '../src/copy.js';
|
|
7
|
+
|
|
8
|
+
await buildFiles(
|
|
9
|
+
await globby(['**/*.mjs', '!_*/**/*', '!node_modules/', '!build/'], {
|
|
10
|
+
gitignore: true,
|
|
11
|
+
ignoreFiles: ['.onlyignore']
|
|
12
|
+
}),
|
|
13
|
+
'build/'
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
await copyFiles(
|
|
17
|
+
await globby(
|
|
18
|
+
[
|
|
19
|
+
'**/*',
|
|
20
|
+
'!**/*.mjs',
|
|
21
|
+
'!_*/**/*',
|
|
22
|
+
'!package.json',
|
|
23
|
+
'!package-lock.json',
|
|
24
|
+
'!node_modules/',
|
|
25
|
+
'!build/'
|
|
26
|
+
],
|
|
27
|
+
{
|
|
28
|
+
gitignore: true,
|
|
29
|
+
ignoreFiles: ['.onlyignore']
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
'build/'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "onlybuild",
|
|
3
|
+
"description": "A zero-config cli for building static websites.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20.x"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"onlybuild": "./bin/index.js"
|
|
11
|
+
},
|
|
12
|
+
"main": "./src/index.js",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"globby": "14.0.1"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"javascript",
|
|
22
|
+
"build",
|
|
23
|
+
"static"
|
|
24
|
+
],
|
|
25
|
+
"authors": [
|
|
26
|
+
{
|
|
27
|
+
"name": "Scott Doxey",
|
|
28
|
+
"email": "hello@scottdoxey.com",
|
|
29
|
+
"homepage": "http://scottdoxey.com/"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"homepage": "https://github.com/neogeek/onlybuild",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git://github.com/neogeek/onlybuild.git"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/build.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string[]} paths
|
|
6
|
+
* @param {string} buildDir
|
|
7
|
+
*/
|
|
8
|
+
export const buildFiles = async (paths, buildDir) => {
|
|
9
|
+
await Promise.all(
|
|
10
|
+
paths.map(async path => {
|
|
11
|
+
const filename = basename(path, '.mjs');
|
|
12
|
+
|
|
13
|
+
const directory =
|
|
14
|
+
filename === 'index'
|
|
15
|
+
? join(buildDir, dirname(path))
|
|
16
|
+
: join(buildDir, dirname(path), filename);
|
|
17
|
+
|
|
18
|
+
const html = (await import(resolve(path))).default;
|
|
19
|
+
|
|
20
|
+
if (typeof html === 'string') {
|
|
21
|
+
await mkdir(directory, { recursive: true });
|
|
22
|
+
|
|
23
|
+
await writeFile(join(directory, `index.html`), html);
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
};
|
package/src/copy.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { copyFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string[]} paths
|
|
6
|
+
* @param {string} buildDir
|
|
7
|
+
*/
|
|
8
|
+
export const copyFiles = async (paths, buildDir) => {
|
|
9
|
+
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
|
+
})
|
|
15
|
+
);
|
|
16
|
+
};
|
package/src/html.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {TemplateStringsArray} strings
|
|
3
|
+
* @param {any[]} values
|
|
4
|
+
*/
|
|
5
|
+
export const html = (strings, ...values) => {
|
|
6
|
+
const processedValues = values.map(value =>
|
|
7
|
+
Array.isArray(value) ? value.join('') : value
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
return strings.reduce(
|
|
11
|
+
(prev, curr, i) => `${prev}${curr}${processedValues[i] || ''}`,
|
|
12
|
+
''
|
|
13
|
+
);
|
|
14
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { html } from './html.js';
|