prepare-package 2.0.1 → 2.0.4

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/dist/build.js CHANGED
@@ -34,7 +34,7 @@ async function build(options) {
34
34
  build.onLoad({ filter: /\.js$/ }, async (args) => {
35
35
  let contents = fs.readFileSync(args.path, 'utf8');
36
36
  contents = contents.replace(/\{version\}/g, version);
37
- return { contents, loader: 'js' };
37
+ return { contents, loader: 'js', watchFiles: [args.path] };
38
38
  });
39
39
  },
40
40
  };
@@ -124,13 +124,39 @@ async function createWatchContexts(options) {
124
124
  const entry = path.resolve(cwd, buildConfig.entry || path.join(config.input || './src', 'index.js'));
125
125
  const formats = buildConfig.formats || ['esm', 'cjs'];
126
126
 
127
- const versionPlugin = {
128
- name: 'version-replace',
127
+ // In watch mode, replace {version} in output files AFTER build (onEnd)
128
+ // instead of intercepting file loading (onLoad), so esbuild's native
129
+ // file watcher can detect source changes.
130
+ let isFirstBuild = true;
131
+ let rebuildTimer = null;
132
+
133
+ const watchVersionPlugin = {
134
+ name: 'version-replace-watch',
129
135
  setup(build) {
130
- build.onLoad({ filter: /\.js$/ }, async (args) => {
131
- let contents = fs.readFileSync(args.path, 'utf8');
132
- contents = contents.replace(/\{version\}/g, version);
133
- return { contents, loader: 'js' };
136
+ build.onEnd((result) => {
137
+ // Replace {version} in the output file
138
+ const outfile = build.initialOptions.outfile;
139
+ if (outfile && fs.existsSync(outfile)) {
140
+ const contents = fs.readFileSync(outfile, 'utf8');
141
+ if (contents.includes('{version}')) {
142
+ fs.writeFileSync(outfile, contents.replace(/\{version\}/g, version));
143
+ }
144
+ }
145
+
146
+ // Skip first build (the "Watching..." message covers it)
147
+ if (isFirstBuild) {
148
+ return;
149
+ }
150
+
151
+ // Debounce rebuild log across all format contexts
152
+ if (result.errors.length > 0) {
153
+ logger.error(chalk.red(`Build failed with ${result.errors.length} error(s)`));
154
+ } else if (!rebuildTimer) {
155
+ rebuildTimer = setTimeout(() => {
156
+ rebuildTimer = null;
157
+ logger.log(chalk.green(`Rebuilt ${packageJSON.name} v${version}`));
158
+ }, 50);
159
+ }
134
160
  });
135
161
  },
136
162
  };
@@ -139,7 +165,7 @@ async function createWatchContexts(options) {
139
165
  entryPoints: [entry],
140
166
  bundle: true,
141
167
  sourcemap: buildConfig.sourcemap || false,
142
- plugins: [versionPlugin],
168
+ plugins: [watchVersionPlugin],
143
169
  external: buildConfig.external || [],
144
170
  };
145
171
 
@@ -195,6 +221,8 @@ async function createWatchContexts(options) {
195
221
  );
196
222
 
197
223
  await Promise.all(contexts.map(ctx => ctx.watch()));
224
+ // Delay flipping the flag so initial onEnd callbacks complete first
225
+ await new Promise(resolve => setTimeout(() => { isFirstBuild = false; resolve(); }, 100));
198
226
 
199
227
  const formatNames = formats.map(f => f.toUpperCase()).join(', ');
200
228
  logger.log(chalk.green(`Watching ${packageJSON.name} v${version} (${formatNames})...`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prepare-package",
3
- "version": "2.0.1",
3
+ "version": "2.0.4",
4
4
  "description": "Prepare a Node.js package before being published",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -11,6 +11,9 @@
11
11
  ".": "./dist/index.js",
12
12
  "./watch": "./dist/watch.js"
13
13
  },
14
+ "files": [
15
+ "dist"
16
+ ],
14
17
  "scripts": {
15
18
  "test": "./node_modules/mocha/bin/mocha test/ --recursive --timeout=10000",
16
19
  "start": "npm run prepare:watch",
package/CHANGELOG.md DELETED
@@ -1,20 +0,0 @@
1
- # CHANGELOG
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
-
7
- ## Changelog Categories
8
-
9
- - `BREAKING` for breaking changes.
10
- - `Added` for new features.
11
- - `Changed` for changes in existing functionality.
12
- - `Deprecated` for soon-to-be removed features.
13
- - `Removed` for now removed features.
14
- - `Fixed` for any bug fixes.
15
- - `Security` in case of vulnerabilities.
16
-
17
- ---
18
- ## [1.0.0] - 2024-06-19
19
- ### Added
20
- - Initial release of the project 🚀
package/CLAUDE.md DELETED
@@ -1,76 +0,0 @@
1
- # prepare-package
2
-
3
- ## Overview
4
- NPM build tool that prepares packages for distribution. Supports two modes: **copy** (file copy with version replacement) and **bundle** (esbuild multi-format builds).
5
-
6
- ## Architecture
7
-
8
- ### Two Modes via `preparePackage.type`
9
- - **`"copy"` (default)**: Copies `src/` to `dist/`, replaces `{version}` in the main file. Used by large projects that don't need bundling (e.g., UJM).
10
- - **`"bundle"`**: Uses esbuild to produce ESM (`index.mjs`), CJS (`index.js`), and/or IIFE (minified, for CDN `<script>` tags). Used by client-side libraries (e.g., chatsy).
11
-
12
- ### Project Structure
13
- ```
14
- src/
15
- index.js # Main entry: resolves config, branches copy vs bundle, safety checks, CDN purge
16
- build.js # Esbuild config generator, version plugin, build() and createWatchContexts()
17
- watch.js # Watch mode: chokidar for copy, esbuild contexts for bundle
18
- cli.js # Interactive CLI for project setup (npx pp / npx prepare-package)
19
- logger.js # Timestamped console logger with chalk colors
20
- dist/ # Copy-mode output of src/ (prepare-package builds itself with copy mode)
21
- ```
22
-
23
- ### CLI (`npx pp` / `npx prepare-package`)
24
- Interactive setup wizard that configures a project's `package.json`:
25
- 1. Asks **copy** or **bundle** mode
26
- 2. Asks source/output directories (defaults: `src`/`dist`)
27
- 3. If bundle: asks formats, auto-derives `globalName` (TitleCase of package name) and `fileName` (`{name}.min.js`)
28
- 4. Writes `preparePackage` config and `prepare`/`prepare:watch` scripts to `package.json`
29
-
30
- ### How It Runs
31
- - **`prepare` script**: Runs on `npm install` and `npm publish` in the consumer's project
32
- - **`postinstall` script**: Runs when prepare-package itself is installed as a dependency. Skips bundle mode (esbuild may not be available yet during install)
33
- - **`prepare:watch` script**: Starts watch mode (chokidar for copy, esbuild `.watch()` for bundle)
34
- - **`bin` commands**: `prepare-package` and `pp` both point to `cli.js`
35
-
36
- ### Consumer Configuration
37
- All config lives in `preparePackage` key in the consumer's `package.json`:
38
-
39
- ```jsonc
40
- {
41
- "preparePackage": {
42
- "input": "src", // Source directory
43
- "output": "dist", // Output directory
44
- "type": "copy", // "copy" (default) or "bundle"
45
- "build": { // Only used when type: "bundle"
46
- "entry": "src/index.js",
47
- "formats": ["esm", "cjs", "iife"],
48
- "target": "es2020",
49
- "platform": "neutral",
50
- "external": [],
51
- "sourcemap": false,
52
- "iife": {
53
- "globalName": "MyLib", // Required for IIFE
54
- "fileName": "my-lib.min.js" // Default: "{name}.min.js"
55
- }
56
- }
57
- }
58
- }
59
- ```
60
-
61
- ### Publish Safety
62
- - Blocks publish if any local `file:` dependencies are found
63
- - Removes sensitive files (`.env`, `.DS_Store`, etc.) from the package
64
- - Purges jsDelivr CDN cache after publish
65
-
66
- ### Key Details
67
- - esbuild is a direct dependency but only `require()`'d inside bundle code paths (lazy-loaded)
68
- - Bundle mode's version plugin replaces `{version}` in all `.js` files at build time
69
- - IIFE build auto-unwraps default export: `GlobalName=GlobalName.default||GlobalName.GlobalName||GlobalName;`
70
- - Copy mode's `{version}` replacement only applies to the main file
71
- - prepare-package builds itself using copy mode (it's both the tool and a consumer of itself)
72
-
73
- ## Conventions
74
- - Self-hosting: prepare-package uses itself (copy mode) to build `src/` → `dist/`
75
- - No breaking changes to copy mode — existing consumers must keep working unchanged
76
- - Bundle mode is opt-in via `type: "bundle"`