@elenajs/bundler 0.9.0 → 1.0.0-rc.2
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 +235 -0
- package/package.json +24 -13
- package/src/cem-analyze.js +16 -6
- package/src/cli.js +44 -11
- package/src/common/load-config.js +66 -11
- package/src/common/validate-config.js +70 -0
- package/src/index.js +5 -5
- package/src/rollup-build.js +116 -24
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://elenajs.com/img/elena-dark.png" alt="Elena" width="558" height="220">
|
|
4
|
+
</source>
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
|
|
6
|
+
</source>
|
|
7
|
+
<img src="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
|
|
8
|
+
</picture>
|
|
9
|
+
|
|
10
|
+
### Bundler for Progressive Web Component libraries built with Elena.
|
|
11
|
+
|
|
12
|
+
<br/>
|
|
13
|
+
|
|
14
|
+
<a href="https://arielsalminen.com"><img src="https://img.shields.io/badge/creator-@arielle-F95B1F" alt="Creator @arielle"/></a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@elenajs/bundler"><img src="https://img.shields.io/npm/v/@elenajs/bundler.svg" alt="Latest version on npm" /></a>
|
|
16
|
+
<a href="https://github.com/getelena/elena/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="Elena is released under the MIT license." /></a>
|
|
17
|
+
<a href="https://github.com/getelena/elena/actions/workflows/tests.yml"><img src="https://github.com/getelena/elena/actions/workflows/tests.yml/badge.svg" alt="Tests status" /></a>
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<br/>
|
|
22
|
+
|
|
23
|
+
<p align="center"><strong>@elenajs/bundler</strong> is the build tool for <a href="https://elenajs.com">Elena</a> Progressive Web Component libraries. It bundles JavaScript and TypeScript source files, minifies CSS, generates a <a href="https://custom-elements-manifest.open-wc.org/">Custom Elements Manifest</a>, and produces TypeScript declarations for Elena components.</p>
|
|
24
|
+
|
|
25
|
+
<br/>
|
|
26
|
+
|
|
27
|
+
## Table of contents
|
|
28
|
+
|
|
29
|
+
- **[Install](#install)**
|
|
30
|
+
- **[CLI usage](#cli-usage)**
|
|
31
|
+
- **[Configuration](#configuration)**
|
|
32
|
+
- **[Options](#options)**
|
|
33
|
+
- **[Build output](#build-output)**
|
|
34
|
+
- **[Programmatic API](#programmatic-api)**
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install --save-dev @elenajs/bundler
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## CLI usage
|
|
43
|
+
|
|
44
|
+
The bundler provides an `elena` CLI binary with `build` and `watch` commands:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx elena build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If no command is provided, `build` is assumed:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx elena
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To start a watch session that rebuilds on file changes:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx elena watch
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Flags
|
|
63
|
+
|
|
64
|
+
| Flag | Description |
|
|
65
|
+
| ------------------ | ------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `--config <path>` | Path to a config file. Defaults to `elena.config.mjs` or `elena.config.js` in the project root. |
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx elena build --config config/elena.config.mjs
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
Create an `elena.config.mjs` (or `elena.config.js`) at the root of your package:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
/**
|
|
80
|
+
* ░ [ELENA]: Bundler configuration
|
|
81
|
+
*
|
|
82
|
+
* @type {import("@elenajs/bundler").ElenaConfig}
|
|
83
|
+
*/
|
|
84
|
+
export default {
|
|
85
|
+
// Source directory scanned for .js/.ts entry files and .css files.
|
|
86
|
+
input: "src",
|
|
87
|
+
|
|
88
|
+
// Rollup output options.
|
|
89
|
+
output: {
|
|
90
|
+
dir: "dist",
|
|
91
|
+
format: "esm",
|
|
92
|
+
sourcemap: true,
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// Entry for the single-file bundle. Set to false to disable.
|
|
96
|
+
bundle: "src/index.js",
|
|
97
|
+
|
|
98
|
+
// Additional Rollup plugins appended after Elena's built-in set.
|
|
99
|
+
// plugins: [],
|
|
100
|
+
|
|
101
|
+
// Custom Elements Manifest options. Set to false to skip entirely.
|
|
102
|
+
// analyze: {
|
|
103
|
+
// plugins: [],
|
|
104
|
+
// },
|
|
105
|
+
|
|
106
|
+
// Browserslist targets for transpilation. Enables syntax transforms
|
|
107
|
+
// (e.g. class fields, optional chaining) to widen browser support.
|
|
108
|
+
// target: ["chrome 71", "firefox 69", "safari 12.1"],
|
|
109
|
+
|
|
110
|
+
// Custom Terser minifier options, merged with the defaults.
|
|
111
|
+
// terser: { ecma: 2020, module: true },
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Options
|
|
116
|
+
|
|
117
|
+
| Option | Type | Default | Description |
|
|
118
|
+
| ------------------ | ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
119
|
+
| `input` | `string` | `"src"` | Source directory to scan for `.js`, `.ts`, and `.css` files. |
|
|
120
|
+
| `output.dir` | `string` | `"dist"` | Output directory for compiled files. |
|
|
121
|
+
| `output.format` | `string` | `"esm"` | Rollup output format. |
|
|
122
|
+
| `output.sourcemap` | `boolean` | `true` | Whether to emit sourcemaps. |
|
|
123
|
+
| `bundle` | `string \| false` | `"src/index.js"` | Entry point for the single-file bundle. Auto-detects `src/index.ts` if no `.js` entry exists. Set to `false` to disable. |
|
|
124
|
+
| `plugins` | `Plugin[]` | `[]` | Additional Rollup plugins appended after the built-in set. |
|
|
125
|
+
| `analyze` | `object \| false` | `{ plugins: [] }` | CEM analysis options. Set to `false` to skip Custom Elements Manifest generation, TypeScript declarations, and JSX types entirely. |
|
|
126
|
+
| `analyze.plugins` | `Plugin[]` | `[]` | Additional CEM analyzer plugins. |
|
|
127
|
+
| `target` | `string \| string[] \| false` | `false` | Browserslist target(s) for transpilation. When set, enables syntax transforms (e.g. class fields, optional chaining) via `@babel/preset-env` to widen browser support. Example: `["chrome 71", "firefox 69", "safari 12.1"]`. |
|
|
128
|
+
| `terser` | `object` | `{ ecma: 2020, module: true }` | Custom Terser minifier options, merged with the defaults. See the [Terser API docs](https://terser.org/docs/api-reference/) for available options. |
|
|
129
|
+
|
|
130
|
+
## Build output
|
|
131
|
+
|
|
132
|
+
Running `elena build` produces:
|
|
133
|
+
|
|
134
|
+
| File | Description |
|
|
135
|
+
| --------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `dist/*.js` | Individual ES modules for each source file. |
|
|
137
|
+
| `dist/*.css` | Minified individual CSS files. |
|
|
138
|
+
| `dist/bundle.js` | Single-file JavaScript bundle _(optional)_. |
|
|
139
|
+
| `dist/bundle.css` | Concatenated and minified CSS bundle. CSS files imported as CSS Module Scripts (`with { type: "css" }`) for Shadow DOM are excluded. |
|
|
140
|
+
| `dist/custom-elements.json` | [Custom Elements Manifest](https://custom-elements-manifest.open-wc.org/) describing all components. |
|
|
141
|
+
| `dist/custom-elements.d.ts` | JSX integration types mapping tag names to prop types. |
|
|
142
|
+
| `dist/*.d.ts` | Per-component TypeScript declarations with typed props and events. |
|
|
143
|
+
|
|
144
|
+
> **Note:** CSS files that are imported as CSS Module Scripts for Shadow DOM use (`import styles from "./button.css" with { type: "css" }`) are inlined as `CSSStyleSheet` objects in the JavaScript output and excluded from `bundle.css`. Individual `.css` files are still emitted.
|
|
145
|
+
|
|
146
|
+
## TypeScript support
|
|
147
|
+
|
|
148
|
+
The bundler supports both JavaScript and TypeScript source files. When `.ts` files are detected in the source directory, the bundler automatically transpiles them to JavaScript using `@rollup/plugin-typescript`. The output is identical to what you get from JavaScript sources.
|
|
149
|
+
|
|
150
|
+
To use TypeScript, write your components with inline type annotations instead of JSDoc:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { Elena, html } from "@elenajs/core";
|
|
154
|
+
|
|
155
|
+
export default class Button extends Elena(HTMLElement) {
|
|
156
|
+
static tagName = "elena-button";
|
|
157
|
+
static props = ["variant"];
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The style variant of the component.
|
|
161
|
+
* @attribute
|
|
162
|
+
*/
|
|
163
|
+
variant: "default" | "primary" | "danger" = "default";
|
|
164
|
+
|
|
165
|
+
render() {
|
|
166
|
+
return html`<button>${this.text}</button>`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
Button.define();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
A `tsconfig.json` is required in the project root. A minimal configuration:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"compilerOptions": {
|
|
177
|
+
"target": "ES2020",
|
|
178
|
+
"module": "ESNext",
|
|
179
|
+
"moduleResolution": "bundler",
|
|
180
|
+
"skipLibCheck": true
|
|
181
|
+
},
|
|
182
|
+
"include": ["src"]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
> **Note:** The bundler handles TypeScript declarations separately via the CEM analyzer, you do not need `declaration: true` in your `tsconfig.json`.
|
|
187
|
+
|
|
188
|
+
## Programmatic API
|
|
189
|
+
|
|
190
|
+
The bundler exports its internals so you can integrate it into your own build scripts:
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
import {
|
|
194
|
+
createRollupConfig,
|
|
195
|
+
runRollupBuild,
|
|
196
|
+
watchRollupBuild,
|
|
197
|
+
createCemConfig,
|
|
198
|
+
runCemAnalyze,
|
|
199
|
+
} from "@elenajs/bundler";
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Sub-path imports are also available:
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
import { createRollupConfig, runRollupBuild, watchRollupBuild } from "@elenajs/bundler/rollup";
|
|
206
|
+
import { createCemConfig, runCemAnalyze } from "@elenajs/bundler/cem";
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### `createRollupConfig(options?)`
|
|
210
|
+
|
|
211
|
+
Returns a Rollup configuration array. Useful if you want to wrap or extend the config in a custom `rollup.config.js`.
|
|
212
|
+
|
|
213
|
+
### `runRollupBuild(config)`
|
|
214
|
+
|
|
215
|
+
Runs both build phases (individual modules + optional single-file bundle) programmatically.
|
|
216
|
+
|
|
217
|
+
### `watchRollupBuild(config, opts?)`
|
|
218
|
+
|
|
219
|
+
Starts a Rollup watch session that rebuilds on file changes. Returns the Rollup watcher instance. Pass `opts.onRebuild` as an async callback to run after each successful rebuild (e.g. to re-run CEM analysis).
|
|
220
|
+
|
|
221
|
+
### `createCemConfig(options?)`
|
|
222
|
+
|
|
223
|
+
Returns the Custom Elements Manifest analyzer configuration object.
|
|
224
|
+
|
|
225
|
+
### `runCemAnalyze(config, cwd?)`
|
|
226
|
+
|
|
227
|
+
Runs the CEM analysis and writes `custom-elements.json`, `custom-elements.d.ts`, and per-component `.d.ts` files.
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|
|
232
|
+
|
|
233
|
+
## Copyright
|
|
234
|
+
|
|
235
|
+
Copyright © 2026 [Ariel Salminen](https://arielsalminen.com)
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elenajs/bundler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
4
|
"description": "Bundler for Progressive Web Component libraries built with Elena.",
|
|
5
5
|
"author": "Elena <hi@elenajs.com>",
|
|
6
6
|
"homepage": "https://elenajs.com/",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/getelena/elena.git",
|
|
10
|
+
"directory": "packages/bundler"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/getelena/elena/issues"
|
|
14
|
+
},
|
|
7
15
|
"license": "MIT",
|
|
8
16
|
"publishConfig": {
|
|
9
17
|
"access": "public"
|
|
@@ -27,24 +35,27 @@
|
|
|
27
35
|
"test": "vitest run"
|
|
28
36
|
},
|
|
29
37
|
"dependencies": {
|
|
38
|
+
"@babel/core": "7.29.0",
|
|
39
|
+
"@babel/preset-env": "7.29.0",
|
|
30
40
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
31
|
-
"@elenajs/plugin-cem-define": "^0.
|
|
32
|
-
"@elenajs/plugin-cem-tag": "^0.
|
|
33
|
-
"@elenajs/plugin-cem-typescript": "^0.
|
|
34
|
-
"@elenajs/plugin-rollup-css": "^0.
|
|
41
|
+
"@elenajs/plugin-cem-define": "^1.0.0-beta.2",
|
|
42
|
+
"@elenajs/plugin-cem-tag": "^1.0.0-beta.2",
|
|
43
|
+
"@elenajs/plugin-cem-typescript": "^1.0.0-beta.2",
|
|
44
|
+
"@elenajs/plugin-rollup-css": "^1.0.0-beta.2",
|
|
45
|
+
"@rollup/plugin-babel": "7.0.0",
|
|
35
46
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
36
|
-
"@rollup/plugin-terser": "0.
|
|
37
|
-
"@rollup/plugin-typescript": "
|
|
47
|
+
"@rollup/plugin-terser": "1.0.0",
|
|
48
|
+
"@rollup/plugin-typescript": "12.3.0",
|
|
38
49
|
"custom-element-jsx-integration": "1.6.0",
|
|
39
50
|
"globby": "16.1.1",
|
|
40
|
-
"rollup": "4.
|
|
41
|
-
"rollup-plugin-minify-html-literals-v3": "
|
|
51
|
+
"rollup": "4.59.0",
|
|
52
|
+
"rollup-plugin-minify-html-literals-v3": "1.3.4",
|
|
42
53
|
"rollup-plugin-summary": "3.0.1",
|
|
43
|
-
"tslib": "
|
|
44
|
-
"typescript": "
|
|
54
|
+
"tslib": "2.8.1",
|
|
55
|
+
"typescript": "5.9.3"
|
|
45
56
|
},
|
|
46
57
|
"devDependencies": {
|
|
47
|
-
"vitest": "4.0
|
|
58
|
+
"vitest": "4.1.0"
|
|
48
59
|
},
|
|
49
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "18e13f305c8823f7633c739f2ec61cec2420267b"
|
|
50
61
|
}
|
package/src/cem-analyze.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ██████████ ████
|
|
3
3
|
* ░░███░░░░░█░░███
|
|
4
|
-
* ░███ █ ░
|
|
5
|
-
* ░██████
|
|
6
|
-
* ░███░░█
|
|
7
|
-
* ░███ ░ █
|
|
4
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
5
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
6
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
7
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
8
8
|
* ██████████ █████░░██████ ████ █████░░████████
|
|
9
9
|
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
10
10
|
*
|
|
@@ -23,8 +23,7 @@ import { elenaTypeScriptPlugin } from "@elenajs/plugin-cem-typescript";
|
|
|
23
23
|
import { color } from "./common/color.js";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* users who still call the CEM CLI with a thin `elena.config.js` wrapper.
|
|
26
|
+
* Return the CEM config object for the given Elena config.
|
|
28
27
|
*
|
|
29
28
|
* @param {import("./common/load-config.js").ElenaConfig} [options]
|
|
30
29
|
* @returns {object} CEM config object
|
|
@@ -60,10 +59,21 @@ export function createCemConfig(options = {}) {
|
|
|
60
59
|
* @returns {Promise<void>}
|
|
61
60
|
*/
|
|
62
61
|
export async function runCemAnalyze(config, cwd = process.cwd()) {
|
|
62
|
+
if (config.analyze === false) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
63
66
|
const src = config.input ?? "src";
|
|
64
67
|
const outdir = config.output?.dir ?? "dist";
|
|
65
68
|
const extraPlugins = config.analyze?.plugins ?? [];
|
|
66
69
|
|
|
70
|
+
const srcPath = resolve(cwd, src);
|
|
71
|
+
if (!existsSync(srcPath)) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`░█ [ELENA]: Input directory "${src}" does not exist. Check your "input" config option.`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
console.log(` `);
|
|
68
78
|
console.log(color(`░█ [ELENA]: Analyzing the build output...`));
|
|
69
79
|
console.log(color(`░█ [ELENA]: Generating Custom Elements Manifest...`));
|
package/src/cli.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* ██████████ ████
|
|
5
5
|
* ░░███░░░░░█░░███
|
|
6
|
-
* ░███ █ ░
|
|
7
|
-
* ░██████
|
|
8
|
-
* ░███░░█
|
|
9
|
-
* ░███ ░ █
|
|
6
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
7
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
8
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
9
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
10
10
|
* ██████████ █████░░██████ ████ █████░░████████
|
|
11
11
|
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
12
12
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { loadConfig } from "./common/load-config.js";
|
|
18
|
-
import { runRollupBuild } from "./rollup-build.js";
|
|
18
|
+
import { runRollupBuild, watchRollupBuild } from "./rollup-build.js";
|
|
19
19
|
import { runCemAnalyze } from "./cem-analyze.js";
|
|
20
20
|
import { color } from "./common/color.js";
|
|
21
21
|
|
|
@@ -30,21 +30,54 @@ const BANNER = `
|
|
|
30
30
|
░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
31
31
|
`;
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
const command = args.find(a => !a.startsWith("--")) ?? "build";
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
const configIdx = args.indexOf("--config");
|
|
37
|
+
const configPath = configIdx !== -1 ? args[configIdx + 1] : undefined;
|
|
38
|
+
|
|
39
|
+
/** Loads the Elena config and runs the build or watch. */
|
|
36
40
|
async function main() {
|
|
37
|
-
if (command !== "build") {
|
|
38
|
-
console.error(
|
|
41
|
+
if (command !== "build" && command !== "watch") {
|
|
42
|
+
console.error(
|
|
43
|
+
`░█ [ELENA]: Unknown command: ${command}. Usage: elena [build|watch] [--config <path>]`
|
|
44
|
+
);
|
|
39
45
|
process.exit(1);
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
console.log(color(BANNER));
|
|
43
49
|
|
|
44
|
-
const config = await loadConfig(process.cwd());
|
|
50
|
+
const config = await loadConfig(process.cwd(), configPath);
|
|
51
|
+
|
|
52
|
+
if (command === "watch") {
|
|
53
|
+
const onRebuild =
|
|
54
|
+
config.analyze !== false
|
|
55
|
+
? async cfg => {
|
|
56
|
+
try {
|
|
57
|
+
await runCemAnalyze(cfg);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error(err);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
: undefined;
|
|
63
|
+
|
|
64
|
+
const watcher = watchRollupBuild(config, { onRebuild });
|
|
65
|
+
|
|
66
|
+
process.on("SIGINT", () => {
|
|
67
|
+
watcher.close();
|
|
68
|
+
process.exit(0);
|
|
69
|
+
});
|
|
70
|
+
process.on("SIGTERM", () => {
|
|
71
|
+
watcher.close();
|
|
72
|
+
process.exit(0);
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
45
76
|
|
|
46
77
|
await runRollupBuild(config);
|
|
47
|
-
|
|
78
|
+
if (config.analyze !== false) {
|
|
79
|
+
await runCemAnalyze(config);
|
|
80
|
+
}
|
|
48
81
|
}
|
|
49
82
|
|
|
50
83
|
main().catch(err => {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { pathToFileURL } from "url";
|
|
2
2
|
import { resolve } from "path";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
|
+
import { color } from "./color.js";
|
|
5
|
+
import { validateConfig } from "./validate-config.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* @typedef {object} ElenaOutputConfig
|
|
@@ -21,7 +23,13 @@ import { existsSync } from "fs";
|
|
|
21
23
|
* @property {ElenaOutputConfig} [output] Rollup output options.
|
|
22
24
|
* @property {string|false} [bundle] Entry for the single-file bundle; `false` to disable.
|
|
23
25
|
* @property {import("rollup").Plugin[]} [plugins] Additional Rollup plugins appended after built-ins.
|
|
24
|
-
* @property {ElenaAnalyzeConfig} [analyze] CEM analysis options.
|
|
26
|
+
* @property {ElenaAnalyzeConfig|false} [analyze] CEM analysis options; `false` to skip analysis.
|
|
27
|
+
* @property {string | string[] | false} [target] Browserslist target(s) for transpilation via
|
|
28
|
+
* `@babel/preset-env`. When set, enables syntax transforms (e.g. class fields, optional
|
|
29
|
+
* chaining) to widen browser support. Set to `false` (default) to skip transpilation.
|
|
30
|
+
* Example: `["chrome 71", "firefox 69", "safari 12.1"]`
|
|
31
|
+
* @property {object} [terser] Custom Terser minifier options, merged with the defaults
|
|
32
|
+
* `{ ecma: 2020, module: true }`.
|
|
25
33
|
*/
|
|
26
34
|
|
|
27
35
|
/** @type {Required<ElenaConfig>} */
|
|
@@ -31,29 +39,76 @@ const DEFAULTS = {
|
|
|
31
39
|
bundle: "src/index.js",
|
|
32
40
|
plugins: [],
|
|
33
41
|
analyze: { plugins: [] },
|
|
42
|
+
target: false,
|
|
43
|
+
terser: { ecma: 2020, module: true },
|
|
34
44
|
};
|
|
35
45
|
|
|
36
46
|
/**
|
|
37
|
-
*
|
|
47
|
+
* Merges user config with defaults.
|
|
48
|
+
*
|
|
49
|
+
* @param {ElenaConfig} user
|
|
50
|
+
* @returns {Required<ElenaConfig>}
|
|
51
|
+
*/
|
|
52
|
+
function mergeConfig(user) {
|
|
53
|
+
return {
|
|
54
|
+
...DEFAULTS,
|
|
55
|
+
...user,
|
|
56
|
+
output: { ...DEFAULTS.output, ...user.output },
|
|
57
|
+
analyze: user.analyze === false ? false : { ...DEFAULTS.analyze, ...user.analyze },
|
|
58
|
+
terser: { ...DEFAULTS.terser, ...user.terser },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Loads and imports a config file, returning the merged config.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} configPath
|
|
66
|
+
* @returns {Promise<Required<ElenaConfig>>}
|
|
67
|
+
*/
|
|
68
|
+
async function importConfig(configPath) {
|
|
69
|
+
const mod = await import(pathToFileURL(configPath).href);
|
|
70
|
+
const user = mod.default ?? {};
|
|
71
|
+
validateConfig(user);
|
|
72
|
+
return mergeConfig(user);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Loads the Elena config from the specified path, or from
|
|
77
|
+
* `elena.config.mjs` / `elena.config.js` in `cwd`,
|
|
38
78
|
* falling back to defaults if no config file is found.
|
|
39
79
|
*
|
|
40
80
|
* @param {string} [cwd]
|
|
81
|
+
* @param {string} [explicitPath]
|
|
41
82
|
* @returns {Promise<Required<ElenaConfig>>}
|
|
42
83
|
*/
|
|
43
|
-
export async function loadConfig(cwd = process.cwd()) {
|
|
84
|
+
export async function loadConfig(cwd = process.cwd(), explicitPath) {
|
|
85
|
+
if (explicitPath) {
|
|
86
|
+
const configPath = resolve(cwd, explicitPath);
|
|
87
|
+
if (!existsSync(configPath)) {
|
|
88
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
89
|
+
}
|
|
90
|
+
return importConfig(configPath);
|
|
91
|
+
}
|
|
92
|
+
|
|
44
93
|
for (const name of ["elena.config.mjs", "elena.config.js"]) {
|
|
45
94
|
const configPath = resolve(cwd, name);
|
|
46
95
|
if (!existsSync(configPath)) {
|
|
47
96
|
continue;
|
|
48
97
|
}
|
|
49
|
-
|
|
50
|
-
const user = mod.default ?? {};
|
|
51
|
-
return {
|
|
52
|
-
...DEFAULTS,
|
|
53
|
-
...user,
|
|
54
|
-
output: { ...DEFAULTS.output, ...user.output },
|
|
55
|
-
analyze: { ...DEFAULTS.analyze, ...user.analyze },
|
|
56
|
-
};
|
|
98
|
+
return importConfig(configPath);
|
|
57
99
|
}
|
|
100
|
+
|
|
101
|
+
const wrongExtensions = [".ts", ".json", ".yaml", ".yml", ".cjs"];
|
|
102
|
+
for (const ext of wrongExtensions) {
|
|
103
|
+
const wrongPath = resolve(cwd, `elena.config${ext}`);
|
|
104
|
+
if (existsSync(wrongPath)) {
|
|
105
|
+
console.warn(
|
|
106
|
+
color(`░█ [ELENA]: Found "elena.config${ext}" but only .mjs and .js are supported.`)
|
|
107
|
+
);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log(color(`░█ [ELENA]: No config file found, using defaults.`));
|
|
58
113
|
return { ...DEFAULTS };
|
|
59
114
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { color } from "./color.js";
|
|
2
|
+
|
|
3
|
+
const KNOWN_KEYS = new Set(["input", "output", "bundle", "plugins", "analyze", "target", "terser"]);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validates a raw user config and throws on invalid values.
|
|
7
|
+
* Logs warnings for unknown keys.
|
|
8
|
+
*
|
|
9
|
+
* @param {Record<string, unknown>} config
|
|
10
|
+
*/
|
|
11
|
+
export function validateConfig(config) {
|
|
12
|
+
for (const key of Object.keys(config)) {
|
|
13
|
+
if (!KNOWN_KEYS.has(key)) {
|
|
14
|
+
console.warn(color(`░█ [ELENA]: Unknown config option "${key}".`));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (config.input !== undefined && typeof config.input !== "string") {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`░█ [ELENA]: Invalid config: "input" must be a string, got ${typeof config.input}.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (config.output !== undefined) {
|
|
25
|
+
if (typeof config.output !== "object" || config.output === null) {
|
|
26
|
+
throw new Error(`░█ [ELENA]: Invalid config: "output" must be an object.`);
|
|
27
|
+
}
|
|
28
|
+
if (config.output.dir !== undefined && typeof config.output.dir !== "string") {
|
|
29
|
+
throw new Error(`░█ [ELENA]: Invalid config: "output.dir" must be a string.`);
|
|
30
|
+
}
|
|
31
|
+
if (config.output.format !== undefined && typeof config.output.format !== "string") {
|
|
32
|
+
throw new Error(`░█ [ELENA]: Invalid config: "output.format" must be a string.`);
|
|
33
|
+
}
|
|
34
|
+
if (config.output.sourcemap !== undefined && typeof config.output.sourcemap !== "boolean") {
|
|
35
|
+
throw new Error(`░█ [ELENA]: Invalid config: "output.sourcemap" must be a boolean.`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (config.bundle !== undefined && typeof config.bundle !== "string" && config.bundle !== false) {
|
|
40
|
+
throw new Error(`░█ [ELENA]: Invalid config: "bundle" must be a string or false.`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (config.plugins !== undefined && !Array.isArray(config.plugins)) {
|
|
44
|
+
throw new Error(`░█ [ELENA]: Invalid config: "plugins" must be an array.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (config.analyze !== undefined && config.analyze !== false) {
|
|
48
|
+
if (typeof config.analyze !== "object" || config.analyze === null) {
|
|
49
|
+
throw new Error(`░█ [ELENA]: Invalid config: "analyze" must be an object or false.`);
|
|
50
|
+
}
|
|
51
|
+
if (config.analyze.plugins !== undefined && !Array.isArray(config.analyze.plugins)) {
|
|
52
|
+
throw new Error(`░█ [ELENA]: Invalid config: "analyze.plugins" must be an array.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.target !== undefined && config.target !== false) {
|
|
57
|
+
if (typeof config.target !== "string" && !Array.isArray(config.target)) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`░█ [ELENA]: Invalid config: "target" must be a string, array of strings, or false.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
config.terser !== undefined &&
|
|
66
|
+
(typeof config.terser !== "object" || config.terser === null)
|
|
67
|
+
) {
|
|
68
|
+
throw new Error(`░█ [ELENA]: Invalid config: "terser" must be an object.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ██████████ ████
|
|
3
3
|
* ░░███░░░░░█░░███
|
|
4
|
-
* ░███ █ ░
|
|
5
|
-
* ░██████
|
|
6
|
-
* ░███░░█
|
|
7
|
-
* ░███ ░ █
|
|
4
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
5
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
6
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
7
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
8
8
|
* ██████████ █████░░██████ ████ █████░░████████
|
|
9
9
|
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
10
10
|
*
|
|
@@ -12,5 +12,5 @@
|
|
|
12
12
|
* https://elenajs.com
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
export { createRollupConfig, runRollupBuild } from "./rollup-build.js";
|
|
15
|
+
export { createRollupConfig, runRollupBuild, watchRollupBuild } from "./rollup-build.js";
|
|
16
16
|
export { createCemConfig, runCemAnalyze } from "./cem-analyze.js";
|
package/src/rollup-build.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ██████████ ████
|
|
3
3
|
* ░░███░░░░░█░░███
|
|
4
|
-
* ░███ █ ░
|
|
5
|
-
* ░██████
|
|
6
|
-
* ░███░░█
|
|
7
|
-
* ░███ ░ █
|
|
4
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
5
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
6
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
7
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
8
8
|
* ██████████ █████░░██████ ████ █████░░████████
|
|
9
9
|
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
10
10
|
*
|
|
@@ -13,14 +13,20 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { existsSync, readdirSync } from "fs";
|
|
16
|
-
import { rollup } from "rollup";
|
|
16
|
+
import { rollup, watch } from "rollup";
|
|
17
17
|
import resolve from "@rollup/plugin-node-resolve";
|
|
18
18
|
import terser from "@rollup/plugin-terser";
|
|
19
19
|
import typescript from "@rollup/plugin-typescript";
|
|
20
20
|
import minifyHtmlLiterals from "rollup-plugin-minify-html-literals-v3";
|
|
21
21
|
import summary from "rollup-plugin-summary";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
cssPlugin,
|
|
24
|
+
cssBundlePlugin,
|
|
25
|
+
cssModuleScriptPlugin,
|
|
26
|
+
cssStaticStylesPlugin,
|
|
27
|
+
} from "@elenajs/plugin-rollup-css";
|
|
23
28
|
import { color } from "./common/color.js";
|
|
29
|
+
import babel from "@rollup/plugin-babel";
|
|
24
30
|
|
|
25
31
|
const TREESHAKE = {
|
|
26
32
|
moduleSideEffects: false,
|
|
@@ -28,7 +34,7 @@ const TREESHAKE = {
|
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
/**
|
|
31
|
-
*
|
|
37
|
+
* Suppress noisy Rollup warnings.
|
|
32
38
|
*
|
|
33
39
|
* @param {import("rollup").RollupWarning} warning
|
|
34
40
|
* @param {function} warn
|
|
@@ -41,9 +47,9 @@ function onwarn(warning, warn) {
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
/**
|
|
44
|
-
*
|
|
50
|
+
* Build the plugin list for a single Rollup build target.
|
|
45
51
|
*
|
|
46
|
-
* @param {{ src: string; outdir: string; hasSummary: boolean; includeCssBundle: boolean; extraPlugins?: import("rollup").Plugin[]; hasTs?: boolean }} opts
|
|
52
|
+
* @param {{ src: string; outdir: string; hasSummary: boolean; includeCssBundle: boolean; extraPlugins?: import("rollup").Plugin[]; hasTs?: boolean; target?: string | string[] | false }} opts
|
|
47
53
|
* @returns {import("rollup").Plugin[]}
|
|
48
54
|
*/
|
|
49
55
|
function buildPlugins({
|
|
@@ -53,8 +59,10 @@ function buildPlugins({
|
|
|
53
59
|
includeCssBundle,
|
|
54
60
|
extraPlugins = [],
|
|
55
61
|
hasTs = false,
|
|
62
|
+
target = false,
|
|
63
|
+
terserOpts = { ecma: 2020, module: true },
|
|
56
64
|
}) {
|
|
57
|
-
const plugins = [resolve({ extensions: [".js", ".ts", ".css"] })];
|
|
65
|
+
const plugins = [cssModuleScriptPlugin(), resolve({ extensions: [".js", ".ts", ".css"] })];
|
|
58
66
|
|
|
59
67
|
if (hasTs) {
|
|
60
68
|
plugins.push(
|
|
@@ -69,17 +77,30 @@ function buildPlugins({
|
|
|
69
77
|
);
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
if (target) {
|
|
81
|
+
plugins.push(
|
|
82
|
+
babel({
|
|
83
|
+
babelHelpers: "bundled",
|
|
84
|
+
presets: [["@babel/preset-env", { targets: target, bugfixes: true, modules: false }]],
|
|
85
|
+
extensions: [".js", ".ts"],
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
plugins.push(
|
|
91
|
+
cssStaticStylesPlugin(),
|
|
73
92
|
minifyHtmlLiterals({
|
|
74
93
|
options: {
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
shouldMinify: template => {
|
|
95
|
+
const tag = template.tag && template.tag.toLowerCase();
|
|
96
|
+
return (
|
|
97
|
+
(tag && (tag.includes("html") || tag.includes("svg"))) ||
|
|
98
|
+
template.parts.some(({ text }) => /<[a-z]/i.test(text))
|
|
99
|
+
);
|
|
100
|
+
},
|
|
77
101
|
},
|
|
78
102
|
}),
|
|
79
|
-
terser(
|
|
80
|
-
ecma: 2020,
|
|
81
|
-
module: true,
|
|
82
|
-
}),
|
|
103
|
+
terser(terserOpts),
|
|
83
104
|
cssPlugin(src)
|
|
84
105
|
);
|
|
85
106
|
|
|
@@ -87,7 +108,6 @@ function buildPlugins({
|
|
|
87
108
|
plugins.push(cssBundlePlugin(src, "bundle.css"));
|
|
88
109
|
}
|
|
89
110
|
|
|
90
|
-
// User-provided plugins are appended after built-ins, before summary.
|
|
91
111
|
plugins.push(...extraPlugins);
|
|
92
112
|
|
|
93
113
|
if (hasSummary) {
|
|
@@ -98,10 +118,9 @@ function buildPlugins({
|
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
/**
|
|
101
|
-
*
|
|
102
|
-
* users who want to call `rollup -c` with a thin wrapper config file.
|
|
121
|
+
* Return the Rollup config array for the given Elena config.
|
|
103
122
|
*
|
|
104
|
-
* @param {import("./
|
|
123
|
+
* @param {import("./common/load-config.js").ElenaConfig} [options]
|
|
105
124
|
* @returns {import("rollup").RollupOptions[]}
|
|
106
125
|
*/
|
|
107
126
|
export function createRollupConfig(options = {}) {
|
|
@@ -111,6 +130,14 @@ export function createRollupConfig(options = {}) {
|
|
|
111
130
|
const sourcemap = options.output?.sourcemap ?? true;
|
|
112
131
|
let bundle = options.bundle !== undefined ? options.bundle : "src/index.js";
|
|
113
132
|
const extraPlugins = options.plugins ?? [];
|
|
133
|
+
const target = options.target ?? false;
|
|
134
|
+
const terserOpts = options.terser ?? { ecma: 2020, module: true };
|
|
135
|
+
|
|
136
|
+
if (!existsSync(src)) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`░█ [ELENA]: Input directory "${src}" does not exist. Check your "input" config option.`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
114
141
|
|
|
115
142
|
const entries = readdirSync(src, { recursive: true })
|
|
116
143
|
.filter(
|
|
@@ -127,6 +154,12 @@ export function createRollupConfig(options = {}) {
|
|
|
127
154
|
bundle = "src/index.ts";
|
|
128
155
|
}
|
|
129
156
|
|
|
157
|
+
if (bundle && !existsSync(bundle)) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`░█ [ELENA]: Bundle entry "${bundle}" does not exist. Check your "bundle" config option.`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
130
163
|
const configs = [
|
|
131
164
|
{
|
|
132
165
|
input: entries,
|
|
@@ -137,6 +170,8 @@ export function createRollupConfig(options = {}) {
|
|
|
137
170
|
includeCssBundle: true,
|
|
138
171
|
extraPlugins,
|
|
139
172
|
hasTs,
|
|
173
|
+
target,
|
|
174
|
+
terserOpts,
|
|
140
175
|
}),
|
|
141
176
|
output: {
|
|
142
177
|
format,
|
|
@@ -160,6 +195,8 @@ export function createRollupConfig(options = {}) {
|
|
|
160
195
|
includeCssBundle: false,
|
|
161
196
|
extraPlugins,
|
|
162
197
|
hasTs,
|
|
198
|
+
target,
|
|
199
|
+
terserOpts,
|
|
163
200
|
}),
|
|
164
201
|
output: { format, sourcemap, file: `${outdir}/bundle.js` },
|
|
165
202
|
preserveEntrySignatures: "strict",
|
|
@@ -172,10 +209,10 @@ export function createRollupConfig(options = {}) {
|
|
|
172
209
|
}
|
|
173
210
|
|
|
174
211
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
212
|
+
* Run Rollup build targets programmatically using the Rollup Node.js API.
|
|
213
|
+
* Reuse `createRollupConfig` to avoid duplicating config resolution logic.
|
|
177
214
|
*
|
|
178
|
-
* @param {import("./
|
|
215
|
+
* @param {import("./common/load-config.js").ElenaConfig} config
|
|
179
216
|
* @returns {Promise<void>}
|
|
180
217
|
*/
|
|
181
218
|
export async function runRollupBuild(config) {
|
|
@@ -184,6 +221,8 @@ export async function runRollupBuild(config) {
|
|
|
184
221
|
console.log(color(`░█ [ELENA]: Building Progressive Web Components...`));
|
|
185
222
|
console.log(` `);
|
|
186
223
|
|
|
224
|
+
let cache;
|
|
225
|
+
|
|
187
226
|
for (const { output, ...inputOpts } of configs) {
|
|
188
227
|
if (Array.isArray(inputOpts.input)) {
|
|
189
228
|
for (const entry of inputOpts.input) {
|
|
@@ -194,8 +233,61 @@ export async function runRollupBuild(config) {
|
|
|
194
233
|
console.log(` `);
|
|
195
234
|
}
|
|
196
235
|
|
|
197
|
-
const build = await rollup(inputOpts);
|
|
236
|
+
const build = await rollup({ ...inputOpts, cache });
|
|
237
|
+
cache = build.cache;
|
|
198
238
|
await build.write(output);
|
|
199
239
|
await build.close();
|
|
200
240
|
}
|
|
201
241
|
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Start a Rollup watch session using the Rollup Node.js watch API.
|
|
245
|
+
* Rebuild on changes and optionally re-run a callback after build.
|
|
246
|
+
*
|
|
247
|
+
* @param {import("./common/load-config.js").ElenaConfig} config
|
|
248
|
+
* @param {{ onRebuild?: (config: import("./common/load-config.js").ElenaConfig) => Promise<void> }} [opts]
|
|
249
|
+
* @returns {import("rollup").RollupWatcher}
|
|
250
|
+
*/
|
|
251
|
+
export function watchRollupBuild(config, opts = {}) {
|
|
252
|
+
const configs = createRollupConfig(config);
|
|
253
|
+
|
|
254
|
+
console.log(color(`░█ [ELENA]: Watching for changes...`));
|
|
255
|
+
console.log(` `);
|
|
256
|
+
|
|
257
|
+
const watchConfigs = configs.map(({ output, ...inputOpts }) => ({
|
|
258
|
+
...inputOpts,
|
|
259
|
+
output,
|
|
260
|
+
watch: { clearScreen: false },
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
const watcher = watch(watchConfigs);
|
|
264
|
+
|
|
265
|
+
watcher.on("event", async event => {
|
|
266
|
+
if (event.code === "BUNDLE_START") {
|
|
267
|
+
console.log(color(`░█ [ELENA]: Rebuilding...`));
|
|
268
|
+
}
|
|
269
|
+
if (event.code === "BUNDLE_END") {
|
|
270
|
+
console.log(color(`░█ [ELENA]: Build completed in ${event.duration}ms.`));
|
|
271
|
+
await event.result.close();
|
|
272
|
+
if (opts.onRebuild) {
|
|
273
|
+
try {
|
|
274
|
+
await opts.onRebuild(config);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
console.error(err);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (event.code === "ERROR") {
|
|
281
|
+
console.error(color(`░█ [ELENA]: Build error:`));
|
|
282
|
+
console.error(event.error);
|
|
283
|
+
if (event.result) {
|
|
284
|
+
await event.result.close();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (event.code === "END") {
|
|
288
|
+
console.log(color(`░█ [ELENA]: Waiting for changes...`));
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return watcher;
|
|
293
|
+
}
|