Skip to content

Commit f4e0bc4

Browse files
authored
Runtime: ensure modules are initialized only once (#3550)
* Runtime: ensure modules are initialized only once Modules should only be initialized once. * Adds a changeset
1 parent c31819a commit f4e0bc4

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

.changeset/serious-ligers-give.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'snowpack': patch
3+
---
4+
5+
Fixes regression with modules executing more than once

snowpack/src/ssr-loader/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ interface ModuleInstance {
1212

1313
type ModuleInitializer = () => Promise<ModuleInstance>;
1414

15+
function moduleInit(fn: ModuleInitializer) {
16+
let promise: null | Promise<ModuleInstance> = null;
17+
return function() {
18+
return promise || (promise = fn());
19+
};
20+
}
21+
1522
// This function makes it possible to load modules from the snowpack server, for the sake of SSR.
1623
export function createLoader({config, load}: ServerRuntimeConfig): ServerRuntime {
1724
const cache = new Map();
@@ -25,7 +32,7 @@ export function createLoader({config, load}: ServerRuntimeConfig): ServerRuntime
2532
return _load(pathname, urlStack);
2633
}
2734

28-
return async function () {
35+
return moduleInit(async function () {
2936
const mod = await REQUIRE_OR_IMPORT(imported, {
3037
from: config.root || config.workspaceRoot || process.cwd(),
3138
});
@@ -34,7 +41,7 @@ export function createLoader({config, load}: ServerRuntimeConfig): ServerRuntime
3441
exports: mod,
3542
css: [],
3643
};
37-
};
44+
});
3845
}
3946

4047
function invalidateModule(path) {
@@ -62,14 +69,14 @@ export function createLoader({config, load}: ServerRuntimeConfig): ServerRuntime
6269
}
6370
const promise = (async function () {
6471
const loaded = await load(url);
65-
return function () {
72+
return moduleInit(function () {
6673
try {
6774
return initializeModule(url, loaded, urlStack.concat(url));
6875
} catch (e) {
6976
cache.delete(url);
7077
throw e;
7178
}
72-
};
79+
});
7380
})();
7481
cache.set(url, promise);
7582
return promise;

test/snowpack/runtime/runtime.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,38 @@ describe('runtime', () => {
204204
await fixture.cleanup();
205205
}
206206
});
207+
208+
it('Executes scripts only once', async () => {
209+
const fixture = await testRuntimeFixture({
210+
'dep.js': dedent`
211+
export let state = 0;
212+
export default function() {
213+
state++;
214+
};
215+
`,
216+
'one.js': dedent`
217+
import inc from './dep.js';
218+
219+
inc();
220+
`,
221+
'two.js': dedent`
222+
import inc from './dep.js';
223+
224+
inc();
225+
`,
226+
'main.js': dedent`
227+
import './one.js';
228+
import './two.js';
229+
import { state } from './dep.js';
230+
export const val = state;
231+
`,
232+
});
233+
234+
try {
235+
let mod = await fixture.runtime.importModule('/main.js');
236+
expect(mod.exports.val).toEqual(2);
237+
} finally {
238+
await fixture.cleanup();
239+
}
240+
});
207241
});

0 commit comments

Comments
 (0)