@parcel/parcel3 0.0.0 → 0.0.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/bin/parcel3 +227 -0
- package/package.json +26 -7
- package/README.md +0 -45
package/bin/parcel3
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shipped as `bin/parcel3`. Parcel itself is a native executable, published one
|
|
6
|
+
* platform package per target and pulled in through optionalDependencies, so all
|
|
7
|
+
* this file does is hand off to whichever one npm installed for this host.
|
|
8
|
+
*
|
|
9
|
+
* It also tries to take itself out of the loop. Starting Node costs ~30ms on
|
|
10
|
+
* every single `parcel3` invocation, which is a large tax on a tool whose whole
|
|
11
|
+
* point is being fast, so on the first run it rewrites the `node_modules/.bin`
|
|
12
|
+
* entry that launched it into a launcher that execs the binary without Node.
|
|
13
|
+
* See `launcher` for why that launcher looks the way it does.
|
|
14
|
+
*
|
|
15
|
+
* Install scripts would be the natural place for this, but npm and pnpm both
|
|
16
|
+
* block them by default now, so first run is the earliest moment available.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
/** The command, which is also the `node_modules/.bin` entry `optimize` rewrites. */
|
|
23
|
+
const NAME = 'parcel3';
|
|
24
|
+
|
|
25
|
+
/** Prefix of the platform packages. Scoped; only `parcel3` itself is not. */
|
|
26
|
+
const PLATFORM_PACKAGE = '@parcel/parcel3';
|
|
27
|
+
|
|
28
|
+
const EXECUTABLE = process.platform === 'win32' ? 'parcel3.exe' : 'parcel3';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The platform packages that could serve this host, best first.
|
|
32
|
+
*
|
|
33
|
+
* The names are derived rather than listed, matching what `matrix.mjs` builds
|
|
34
|
+
* from the target table: `process.platform` and `process.arch` are already the
|
|
35
|
+
* values npm's `os` and `cpu` fields use, so a new target needs no change here.
|
|
36
|
+
*
|
|
37
|
+
* On Linux the name also depends on the C library, and rather than detect it and
|
|
38
|
+
* trust the answer we try both: npm, pnpm and Bun all honour the `libc` field,
|
|
39
|
+
* so only the right one is installed and the wrong one simply fails to resolve.
|
|
40
|
+
* The musl check just decides which to try first, for the package managers that
|
|
41
|
+
* ignore `libc` and install both.
|
|
42
|
+
*/
|
|
43
|
+
function candidates() {
|
|
44
|
+
const base = `${PLATFORM_PACKAGE}-${process.platform}-${process.arch}`;
|
|
45
|
+
if (process.platform !== 'linux') return [base];
|
|
46
|
+
return isMusl() ? [`${base}-musl`, base] : [base, `${base}-musl`];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Whether this is a musl system. Biome and friends shell out to `ldd --version`
|
|
51
|
+
* for this; a directory listing costs a fraction of a process.
|
|
52
|
+
*/
|
|
53
|
+
function isMusl() {
|
|
54
|
+
try {
|
|
55
|
+
return fs.readdirSync('/lib').some(entry => entry.startsWith('ld-musl-'));
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveBinary() {
|
|
62
|
+
for (const pkg of candidates()) {
|
|
63
|
+
try {
|
|
64
|
+
return require.resolve(`${pkg}/${EXECUTABLE}`);
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const binPath = resolveBinary();
|
|
71
|
+
if (binPath == null) {
|
|
72
|
+
// Both cases land here, and the message covers both: the package is missing
|
|
73
|
+
// either because this platform has no prebuilt binary, or because it was
|
|
74
|
+
// skipped at install time.
|
|
75
|
+
process.stderr.write(
|
|
76
|
+
`Parcel could not find the "${
|
|
77
|
+
candidates()[0]
|
|
78
|
+
}" package, which would hold the parcel3 ` +
|
|
79
|
+
`binary for ${process.platform} ${process.arch}.\n\n` +
|
|
80
|
+
`Either Parcel publishes no binary for this platform, or the one it does publish was not ` +
|
|
81
|
+
`installed: it comes in through optionalDependencies, so --no-optional and --omit=optional ` +
|
|
82
|
+
`both skip it, as does copying node_modules here from a machine of a different platform. ` +
|
|
83
|
+
`Reinstalling on this machine fixes the second case.\n`,
|
|
84
|
+
);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
optimize();
|
|
89
|
+
run();
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Rewrite the `.bin` entry that launched us so it runs the binary directly.
|
|
93
|
+
*
|
|
94
|
+
* Only an entry that can be proven to refer to this file is ever touched, the
|
|
95
|
+
* write goes through a temp file and an atomic rename, and every failure leaves
|
|
96
|
+
* the entry alone - a slow parcel3 is fine, a broken one is not.
|
|
97
|
+
*/
|
|
98
|
+
function optimize() {
|
|
99
|
+
// Windows generates .cmd and .ps1 shims with `node` baked in at install time,
|
|
100
|
+
// so replacing what they point at would only break them.
|
|
101
|
+
if (process.platform === 'win32' || process.env.PARCEL_NO_OPTIMIZE) return;
|
|
102
|
+
|
|
103
|
+
for (const entry of binEntries()) {
|
|
104
|
+
try {
|
|
105
|
+
const stat = fs.lstatSync(entry);
|
|
106
|
+
if (stat.isSymbolicLink()) {
|
|
107
|
+
// npm and Yarn: .bin/parcel3 is a symlink to this file.
|
|
108
|
+
if (fs.realpathSync(entry) !== __filename) continue;
|
|
109
|
+
} else if (stat.isFile()) {
|
|
110
|
+
// pnpm: .bin/parcel3 is a generated sh wrapper that runs `node <this>`.
|
|
111
|
+
if (!wrapsThisFile(fs.readFileSync(entry, 'utf8'))) continue;
|
|
112
|
+
} else {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
replace(entry);
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Whether a generated wrapper points at this file. Package managers write the
|
|
123
|
+
* path relative to their own layout, so the tail below the last `node_modules`
|
|
124
|
+
* is the longest part that is guaranteed to appear verbatim.
|
|
125
|
+
*/
|
|
126
|
+
function wrapsThisFile(contents) {
|
|
127
|
+
const tail = __filename.split(/node_modules[\\/]/).pop();
|
|
128
|
+
return contents.includes(tail) && contents.includes('node');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Every `.bin/parcel3` that could have launched this file. */
|
|
132
|
+
function* binEntries() {
|
|
133
|
+
// What the kernel was handed, before symlinks were resolved: npm and Yarn
|
|
134
|
+
// launch us through the .bin symlink itself.
|
|
135
|
+
const argv1 = process.argv[1];
|
|
136
|
+
if (argv1 && path.basename(path.dirname(argv1)) === '.bin') {
|
|
137
|
+
yield argv1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Otherwise walk up. `node_modules/.bin` covers a hoisted layout; pnpm keeps
|
|
141
|
+
// the package under `node_modules/.pnpm/...` and the bin beside the store
|
|
142
|
+
// rather than next to the package, so that one is checked separately.
|
|
143
|
+
let dir = path.dirname(__filename);
|
|
144
|
+
for (
|
|
145
|
+
let parent = path.dirname(dir);
|
|
146
|
+
parent !== dir;
|
|
147
|
+
parent = path.dirname(dir)
|
|
148
|
+
) {
|
|
149
|
+
const base = path.basename(dir);
|
|
150
|
+
if (base === 'node_modules') yield path.join(dir, '.bin', NAME);
|
|
151
|
+
if (base === '.pnpm') yield path.join(parent, '.bin', NAME);
|
|
152
|
+
dir = parent;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The launcher gets read two different ways and has to work as both.
|
|
158
|
+
*
|
|
159
|
+
* Normally the kernel reads `#!/bin/sh` and sh execs the binary, which is the
|
|
160
|
+
* whole point: no Node anywhere. But an invocation that started just before the
|
|
161
|
+
* rename has already told Node to load this path as its entry module, and Node
|
|
162
|
+
* opens it ~30ms later - after the swap. Writing anything Node cannot parse, a
|
|
163
|
+
* symlink to the binary included, makes those invocations die trying to read a
|
|
164
|
+
* Mach-O or ELF file as JavaScript.
|
|
165
|
+
*
|
|
166
|
+
* So the rest of the file is also valid JavaScript. `":"` is the sh no-op and a
|
|
167
|
+
* bare string in JS; everything after `//` is an sh argument and a JS comment.
|
|
168
|
+
* A straggler falls through to the last line and runs the binary anyway, paying
|
|
169
|
+
* for Node one final time.
|
|
170
|
+
*/
|
|
171
|
+
function launcher(entry) {
|
|
172
|
+
// Relative to the launcher, so the tree stays movable: renaming the project or
|
|
173
|
+
// copying node_modules into an image keeps it working.
|
|
174
|
+
const rel = path.relative(path.dirname(entry), binPath);
|
|
175
|
+
if (/["$`\\\n]/.test(rel)) return null; // not safely quotable for sh
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
'#!/bin/sh\n' +
|
|
179
|
+
`":" //# ; exec "\${0%/*}/${rel}" "$@"\n` +
|
|
180
|
+
`require("child_process").spawnSync(require("path").join(__dirname, ${JSON.stringify(
|
|
181
|
+
rel,
|
|
182
|
+
)}), ` +
|
|
183
|
+
`process.argv.slice(2), {stdio: "inherit"});\n`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Write beside the entry, then rename over it. A concurrent invocation sees
|
|
189
|
+
* either the old entry or the new one, never a half-written file.
|
|
190
|
+
*/
|
|
191
|
+
function replace(entry) {
|
|
192
|
+
const contents = launcher(entry);
|
|
193
|
+
if (contents == null) return;
|
|
194
|
+
|
|
195
|
+
const tmp = `${entry}.${process.pid}.tmp`;
|
|
196
|
+
try {
|
|
197
|
+
fs.writeFileSync(tmp, contents, {mode: 0o755});
|
|
198
|
+
fs.renameSync(tmp, entry);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
try {
|
|
201
|
+
fs.unlinkSync(tmp);
|
|
202
|
+
} catch {}
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function run() {
|
|
208
|
+
const args = process.argv.slice(2);
|
|
209
|
+
|
|
210
|
+
// Replacing this process rather than forking one keeps signals, the exit code
|
|
211
|
+
// and terminal handling native. Node gained execve in 23.11 and never has it
|
|
212
|
+
// on Windows, hence the fallback.
|
|
213
|
+
if (typeof process.execve === 'function') {
|
|
214
|
+
process.execve(binPath, [binPath, ...args], process.env);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const result = require('child_process').spawnSync(binPath, args, {
|
|
218
|
+
stdio: 'inherit',
|
|
219
|
+
});
|
|
220
|
+
if (result.error) throw result.error;
|
|
221
|
+
// Signal death has no exit code of its own; 128 + signal is what a shell reports.
|
|
222
|
+
process.exit(
|
|
223
|
+
result.signal
|
|
224
|
+
? 128 + require('os').constants.signals[result.signal]
|
|
225
|
+
: result.status,
|
|
226
|
+
);
|
|
227
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/parcel3",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Blazing fast, zero configuration web application bundler",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/parcel-bundler/parcel.git"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"parcel3": "bin/parcel3"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">= 18"
|
|
18
|
+
},
|
|
19
|
+
"optionalDependencies": {
|
|
20
|
+
"@parcel/parcel3-darwin-arm64": "0.0.2",
|
|
21
|
+
"@parcel/parcel3-win32-arm64": "0.0.2",
|
|
22
|
+
"@parcel/parcel3-linux-arm64": "0.0.2",
|
|
23
|
+
"@parcel/parcel3-linux-arm64-musl": "0.0.2",
|
|
24
|
+
"@parcel/parcel3-darwin-x64": "0.0.2",
|
|
25
|
+
"@parcel/parcel3-win32-x64": "0.0.2",
|
|
26
|
+
"@parcel/parcel3-linux-x64": "0.0.2",
|
|
27
|
+
"@parcel/parcel3-linux-x64-musl": "0.0.2"
|
|
28
|
+
}
|
|
10
29
|
}
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# @parcel/parcel3
|
|
2
|
-
|
|
3
|
-
## ⚠️ IMPORTANT NOTICE ⚠️
|
|
4
|
-
|
|
5
|
-
**This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
|
|
6
|
-
|
|
7
|
-
This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
This package exists to:
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@parcel/parcel3`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
15
|
-
|
|
16
|
-
## What is OIDC Trusted Publishing?
|
|
17
|
-
|
|
18
|
-
OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
|
|
19
|
-
|
|
20
|
-
## Setup Instructions
|
|
21
|
-
|
|
22
|
-
To properly configure OIDC trusted publishing for this package:
|
|
23
|
-
|
|
24
|
-
1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
28
|
-
|
|
29
|
-
## DO NOT USE THIS PACKAGE
|
|
30
|
-
|
|
31
|
-
This package is a placeholder for OIDC configuration only. It:
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
-
|
|
37
|
-
## More Information
|
|
38
|
-
|
|
39
|
-
For more details about npm's trusted publishing feature, see:
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
**Maintained for OIDC setup purposes only**
|