Skip to content

Commit 4b7bdcd

Browse files
authored
perf(npm): improve npm install -g deno binary startup performance (#32439)
This creates a symlink in the `node_modules/.bin` folder to the deno binary.
1 parent f85c0ca commit 4b7bdcd

File tree

6 files changed

+879
-135
lines changed

6 files changed

+879
-135
lines changed

.github/workflows/npm_publish.yml

Lines changed: 265 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ on:
66
version:
77
description: 'Version'
88
type: string
9+
dry_run:
10+
description: 'Dry run (build and test, but skip publishing to npmjs.org)'
11+
type: boolean
12+
default: true
913
release:
1014
types: [published]
1115

12-
permissions:
13-
id-token: write
14-
1516
jobs:
1617
build:
17-
name: npm publish
18+
name: npm build
1819
runs-on: ubuntu-latest
1920
timeout-minutes: 30
2021

@@ -32,12 +33,269 @@ jobs:
3233
- name: Install Deno
3334
uses: denoland/setup-deno@v2
3435
with:
35-
deno-version: v2.x
36+
deno-version: v2.7.1
37+
38+
- name: Build npm packages
39+
run: ./tools/release/npm/build.ts ${{ inputs.version || '' }}
40+
41+
- name: Upload npm dist artifact
42+
uses: actions/upload-artifact@v6
43+
with:
44+
name: npm-dist
45+
path: tools/release/npm/dist
46+
retention-days: 1
47+
48+
test:
49+
name: 'npm test (${{ matrix.runner }})'
50+
needs: build
51+
runs-on: ${{ matrix.runner }}
52+
timeout-minutes: 15
53+
strategy:
54+
fail-fast: false
55+
matrix:
56+
runner: [ubuntu-latest, macos-latest, windows-latest]
57+
defaults:
58+
run:
59+
shell: bash
60+
61+
steps:
62+
- name: Clone repository
63+
uses: actions/checkout@v6
64+
with:
65+
submodules: false
66+
67+
- name: Install Node
68+
uses: actions/setup-node@v6
69+
with:
70+
node-version: '24.x'
71+
72+
- name: Download npm dist artifact
73+
uses: actions/download-artifact@v6
74+
with:
75+
name: npm-dist
76+
path: tools/release/npm/dist
77+
78+
- name: Write Verdaccio config
79+
run: |
80+
mkdir -p "${{ runner.temp }}/verdaccio/storage"
81+
cat > "${{ runner.temp }}/verdaccio/config.yaml" << 'HEREDOC'
82+
storage: ./storage
83+
uplinks: {}
84+
packages:
85+
'@deno/*':
86+
access: $all
87+
publish: $all
88+
'deno':
89+
access: $all
90+
publish: $all
91+
'**':
92+
access: $all
93+
publish: $all
94+
max_body_size: 200mb
95+
log: { type: stdout, format: pretty, level: warn }
96+
HEREDOC
97+
98+
- name: Start Verdaccio
99+
run: |
100+
npx verdaccio@6 \
101+
--config "${{ runner.temp }}/verdaccio/config.yaml" --listen 4873 &
102+
for i in $(seq 1 30); do
103+
if curl -s http://localhost:4873/-/ping > /dev/null 2>&1; then
104+
echo "Verdaccio is ready"
105+
break
106+
fi
107+
sleep 1
108+
done
109+
110+
- name: Install pnpm
111+
run: |
112+
npm install -g pnpm
113+
PNPM_HOME="${{ runner.temp }}/pnpm-global"
114+
mkdir -p "$PNPM_HOME"
115+
echo "PNPM_HOME=$PNPM_HOME" >> "$GITHUB_ENV"
116+
echo "$PNPM_HOME" >> "$GITHUB_PATH"
117+
118+
- name: Configure npm to use Verdaccio
119+
run: |
120+
npm config set registry http://localhost:4873/
121+
npm config set //localhost:4873/:_authToken dummy-token
122+
123+
- name: Publish packages to Verdaccio
124+
id: publish-verdaccio
125+
run: |
126+
DIST_DIR="tools/release/npm/dist"
127+
for pkg_dir in "$DIST_DIR"/@deno/*/; do
128+
echo "Publishing $(basename "$pkg_dir") to Verdaccio..."
129+
(cd "$pkg_dir" && npm publish --registry http://localhost:4873/)
130+
done
131+
echo "Publishing deno to Verdaccio..."
132+
(cd "$DIST_DIR/deno" && npm publish --registry http://localhost:4873/)
133+
VERSION=$(node -p "require('./$DIST_DIR/deno/package.json').version")
134+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
135+
136+
- name: Test npm install deno
137+
run: |
138+
TEST_DIR="${{ runner.temp }}/npm-test"
139+
mkdir -p "$TEST_DIR"
140+
cd "$TEST_DIR"
141+
npm init -y
142+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
143+
npm install deno@${{ steps.publish-verdaccio.outputs.version }}
144+
ACTUAL="$(npx deno -v)"
145+
echo "$ACTUAL"
146+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
147+
148+
- name: Test deno via bin.cjs fallback
149+
run: |
150+
cd "${{ runner.temp }}/npm-test"
151+
node node_modules/deno/bin.cjs eval "console.log('npm package works')"
152+
153+
- name: Test deno via simulated readonly file system
154+
run: |
155+
TEST_DIR="${{ runner.temp }}/readonly-test"
156+
mkdir -p "$TEST_DIR"
157+
cd "$TEST_DIR"
158+
npm init -y
159+
npm install deno@${{ steps.publish-verdaccio.outputs.version }}
160+
rm -f node_modules/deno/deno*
161+
DENO_SIMULATED_READONLY_FILE_SYSTEM=1 node node_modules/deno/bin.cjs -v
162+
163+
- name: Test npm global install deno
164+
run: |
165+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
166+
npm install -g deno@${{ steps.publish-verdaccio.outputs.version }}
167+
ACTUAL="$(deno -v)"
168+
echo "$ACTUAL"
169+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
170+
deno eval "console.log('global npm install works')"
171+
npm uninstall -g deno
172+
173+
- name: Test npm global install deno (--ignore-scripts)
174+
run: |
175+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
176+
npm install -g --ignore-scripts deno@${{ steps.publish-verdaccio.outputs.version }}
177+
ACTUAL="$(deno -v)"
178+
echo "$ACTUAL"
179+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
180+
deno eval "console.log('global npm install works')"
181+
npm uninstall -g deno
182+
183+
- name: Test pnpm local install deno (without postinstall)
184+
run: |
185+
TEST_DIR="${{ runner.temp }}/pnpm-test-no-scripts"
186+
mkdir -p "$TEST_DIR"
187+
cd "$TEST_DIR"
188+
npm init -y
189+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
190+
pnpm install deno@${{ steps.publish-verdaccio.outputs.version }} --registry http://localhost:4873/
191+
ACTUAL="$(node node_modules/deno/bin.cjs -v)"
192+
echo "$ACTUAL"
193+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
194+
195+
- name: Test pnpm global install deno (without postinstall)
196+
run: |
197+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
198+
pnpm install -g deno@${{ steps.publish-verdaccio.outputs.version }} --registry http://localhost:4873/
199+
ACTUAL="$(node "$PNPM_HOME/global/5/node_modules/deno/bin.cjs" -v)"
200+
echo "$ACTUAL"
201+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
202+
pnpm uninstall -g deno
203+
204+
- name: Allow pnpm build scripts
205+
run: pnpm config set --global onlyBuiltDependencies '["*"]'
206+
207+
- name: Test pnpm local install deno (with postinstall)
208+
run: |
209+
TEST_DIR="${{ runner.temp }}/pnpm-test"
210+
mkdir -p "$TEST_DIR"
211+
cd "$TEST_DIR"
212+
npm init -y
213+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
214+
pnpm install deno@${{ steps.publish-verdaccio.outputs.version }} --registry http://localhost:4873/
215+
ACTUAL="$(pnpm exec deno -v)"
216+
echo "$ACTUAL"
217+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
218+
219+
- name: Test pnpm global install deno (with postinstall)
220+
run: |
221+
EXPECTED_VERSION="deno ${{ steps.publish-verdaccio.outputs.version }}"
222+
pnpm install -g deno@${{ steps.publish-verdaccio.outputs.version }} --registry http://localhost:4873/
223+
ACTUAL="$(deno -v)"
224+
echo "$ACTUAL"
225+
[ "$ACTUAL" = "$EXPECTED_VERSION" ] || { echo "Version mismatch: expected '$EXPECTED_VERSION', got '$ACTUAL'"; exit 1; }
226+
deno eval "console.log('global pnpm install works')"
227+
pnpm uninstall -g deno
228+
229+
- name: Test npm local install deno (PowerShell)
230+
if: runner.os == 'Windows'
231+
shell: pwsh
232+
run: |
233+
cd "${{ runner.temp }}/npm-test"
234+
npx deno -v
235+
npx deno eval "console.log('PowerShell npm local install works')"
236+
237+
- name: Test npm global install deno (PowerShell)
238+
if: runner.os == 'Windows'
239+
shell: pwsh
240+
run: |
241+
npm install -g deno@${{ steps.publish-verdaccio.outputs.version }}
242+
deno -v
243+
deno eval "console.log('PowerShell npm global install works')"
244+
npm uninstall -g deno
245+
246+
- name: Test npm local install deno (cmd)
247+
if: runner.os == 'Windows'
248+
shell: cmd
249+
run: |
250+
cd "${{ runner.temp }}/npm-test"
251+
npx deno -v
252+
npx deno eval "console.log('cmd npm local install works')"
253+
254+
- name: Test npm global install deno (cmd)
255+
if: runner.os == 'Windows'
256+
shell: cmd
257+
run: |
258+
npm install -g deno@${{ steps.publish-verdaccio.outputs.version }}
259+
deno -v
260+
deno eval "console.log('cmd npm global install works')"
261+
npm uninstall -g deno
262+
263+
publish:
264+
name: npm publish
265+
needs: [build, test]
266+
if: ${{ !(inputs.dry_run || false) }}
267+
runs-on: ubuntu-latest
268+
timeout-minutes: 15
269+
permissions:
270+
id-token: write
271+
272+
steps:
273+
- name: Configure git
274+
run: |
275+
git config --global core.symlinks true
276+
git config --global fetch.parallel 32
277+
278+
- name: Clone repository
279+
uses: actions/checkout@v6
280+
with:
281+
submodules: recursive
282+
283+
- name: Install Deno
284+
uses: denoland/setup-deno@v2
285+
with:
286+
deno-version: v2.7.1
287+
36288
- name: Install Node
37289
uses: actions/setup-node@v6
38290
with:
39291
node-version: '24.x'
40292
registry-url: 'https://registry.npmjs.org'
41293

42-
- name: Publish
43-
run: ./tools/release/npm/build.ts ${{ github.event.inputs.version }} --publish
294+
- name: Download npm dist artifact
295+
uses: actions/download-artifact@v6
296+
with:
297+
name: npm-dist
298+
path: tools/release/npm/dist
299+
300+
- name: Publish to npm
301+
run: ./tools/release/npm/build.ts ${{ inputs.version || '' }} --publish-only

0 commit comments

Comments
 (0)