Skip to content

Commit 2db6f66

Browse files
authored
Save downloaded JSON files to cache (codesandbox#1069)
Right now we don't download dynamically downloaded `package.json` files to cache, which causes errors when a sandbox is loaded from cache and a dependency uses a dynamic `package.json` to resolve another dynamically downloaded `js` file. This fixes that by explicitly marking all dynamic `package.json` files as a dependency when they are used for resolving. Fixes codesandbox#1058
1 parent f334d88 commit 2db6f66

File tree

8 files changed

+54
-24
lines changed

8 files changed

+54
-24
lines changed

packages/app/src/sandbox/eval/entities/module.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export type Module = {
44
path: string,
55
code: string,
66
requires?: Array<string>,
7+
downloaded?: boolean,
78
};

packages/app/src/sandbox/eval/manager.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,14 @@ export default class Manager {
495495
return SHIMMED_MODULE;
496496
}
497497

498+
// Quick try
499+
const directPath = pathUtils.join(currentPath, shimmedPath);
500+
const directModulePath = this.transpiledModules[directPath];
501+
if (directModulePath) {
502+
this.cachedPaths[dirredPath][path] = directPath;
503+
return directModulePath.module;
504+
}
505+
498506
try {
499507
resolvedPath = resolve.sync(shimmedPath, {
500508
filename: currentPath,
@@ -558,10 +566,10 @@ export default class Manager {
558566

559567
downloadDependency(
560568
path: string,
561-
currentPath: string,
569+
currentTModule: TranspiledModule,
562570
ignoredExtensions: Array<string> = this.preset.ignoredExtensions
563571
): Promise<TranspiledModule> {
564-
return fetchModule(path, currentPath, this, ignoredExtensions).then(
572+
return fetchModule(path, currentTModule, this, ignoredExtensions).then(
565573
module => this.getTranspiledModule(module)
566574
);
567575
}
@@ -788,7 +796,8 @@ export default class Manager {
788796
if (
789797
!this.manifest.contents[tModule.module.path] ||
790798
(tModule.module.path.endsWith('.js') &&
791-
tModule.module.requires == null)
799+
tModule.module.requires == null) ||
800+
tModule.module.downloaded
792801
) {
793802
// Only save modules that are not precomputed
794803
serializedTModules[tModule.getId()] = tModule.serialize();

packages/app/src/sandbox/eval/npm/fetch-npm-module.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Manifest } from '../manager';
99
import DependencyNotFoundError from '../../errors/dependency-not-found-error';
1010
import getDependencyName from '../utils/get-dependency-name';
1111
import { packageFilter } from '../utils/resolve-utils';
12+
import type { default as TranspiledModule } from '../transpiled-module';
1213

1314
type Meta = {
1415
[path: string]: any,
@@ -128,18 +129,21 @@ function downloadDependency(depName: string, depVersion: string, path: string) {
128129
.then(x => ({
129130
path,
130131
code: x,
132+
downloaded: true,
131133
}));
132134

133135
return packages[path];
134136
}
135137

136138
function resolvePath(
137139
path: string,
138-
currentPath: string,
140+
currentTModule: TranspiledModule,
139141
manager: Manager,
140142
defaultExtensions: Array<string> = ['js', 'jsx', 'json'],
141143
meta = {}
142144
): Promise<string> {
145+
const currentPath = currentTModule.module.path;
146+
143147
return new Promise((res, reject) => {
144148
resolve(
145149
path,
@@ -160,7 +164,10 @@ function resolvePath(
160164
const callback = cb || c;
161165

162166
try {
163-
return callback(null, manager.readFileSync(p));
167+
const tModule = manager.resolveTranspiledModule(p, '/');
168+
tModule.initiators.add(currentTModule);
169+
currentTModule.dependencies.add(tModule);
170+
return callback(null, tModule.module.code);
164171
} catch (e) {
165172
const depPath = p.replace('/node_modules/', '');
166173
const depName = getDependencyName(depPath);
@@ -192,6 +199,10 @@ function resolvePath(
192199

193200
if (module) {
194201
manager.addModule(module);
202+
const tModule = manager.addTranspiledModule(module, '');
203+
204+
tModule.initiators.add(currentTModule);
205+
currentTModule.dependencies.add(tModule);
195206

196207
callback(null, module.code);
197208
return null;
@@ -217,7 +228,7 @@ function resolvePath(
217228
}
218229

219230
async function findDependencyVersion(
220-
currentPath: string,
231+
currentTModule: TranspiledModule,
221232
manager: Manager,
222233
defaultExtensions: Array<string> = ['js', 'jsx', 'json'],
223234
dependencyName: string
@@ -227,7 +238,7 @@ async function findDependencyVersion(
227238
try {
228239
const foundPackageJSONPath = await resolvePath(
229240
pathUtils.join(dependencyName, 'package.json'),
230-
currentPath,
241+
currentTModule,
231242
manager,
232243
defaultExtensions
233244
);
@@ -265,10 +276,11 @@ async function findDependencyVersion(
265276

266277
export default async function fetchModule(
267278
path: string,
268-
currentPath: string,
279+
currentTModule: TranspiledModule,
269280
manager: Manager,
270281
defaultExtensions: Array<string> = ['js', 'jsx', 'json']
271282
): Promise<Module> {
283+
const currentPath = currentTModule.module.path;
272284
// Get the last part of the path as dependency name for paths like
273285
// instantsearch.js/node_modules/lodash/sum.js
274286
// In this case we want to get the lodash dependency info
@@ -277,7 +289,7 @@ export default async function fetchModule(
277289
);
278290

279291
const versionInfo = await findDependencyVersion(
280-
currentPath,
292+
currentTModule,
281293
manager,
282294
defaultExtensions,
283295
dependencyName
@@ -304,7 +316,7 @@ export default async function fetchModule(
304316

305317
const foundPath = await resolvePath(
306318
path,
307-
currentPath,
319+
currentTModule,
308320
manager,
309321
defaultExtensions,
310322
normalizedMeta

packages/app/src/sandbox/eval/presets/angular-cli/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import Preset from '../';
44

55
import angular2Transpiler from '../../transpilers/angular2-template';
66
import typescriptTranspiler from '../../transpilers/typescript';
7-
import babelTranspiler from '../../transpilers/babel';
87
import jsonTranspiler from '../../transpilers/json';
98
import stylesTranspiler from '../../transpilers/style';
109
import sassTranspiler from '../../transpilers/sass';
@@ -214,7 +213,7 @@ export default function initialize() {
214213
]);
215214

216215
preset.registerTranspiler(module => /\.js$/.test(module.path), [
217-
{ transpiler: babelTranspiler },
216+
{ transpiler: typescriptTranspiler },
218217
]);
219218

220219
preset.registerTranspiler(module => /\.json$/.test(module.path), [

packages/app/src/sandbox/eval/transpiled-module.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ export default class TranspiledModule {
422422
} catch (e) {
423423
if (e.type === 'module-not-found' && e.isDependency) {
424424
this.asyncDependencies.push(
425-
manager.downloadDependency(e.path, this.module.path)
425+
manager.downloadDependency(e.path, this)
426426
);
427427
} else {
428428
// Don't throw the error, we want to throw this error during evaluation
@@ -675,7 +675,11 @@ export default class TranspiledModule {
675675
!isESModule(this.module.code)
676676
) {
677677
if (process.env.NODE_ENV === 'development') {
678-
console.warn('[WARN] Sandpack: loading an untranspiled module');
678+
console.warn(
679+
`[WARN] Sandpack: loading an untranspiled module: ${
680+
this.module.path
681+
}`
682+
);
679683
}
680684
// This code is probably required as a dynamic require. Since we can
681685
// assume that node_modules dynamic requires are only done for node
@@ -891,7 +895,8 @@ export default class TranspiledModule {
891895
if (
892896
this.initiators.size === 0 &&
893897
this.transpilationInitiators.size === 0 &&
894-
!this.isEntry
898+
!this.isEntry &&
899+
!manager.isFirstLoad
895900
) {
896901
// Remove the module from the transpiler if it's not used anymore
897902
debug(`Removing '${this.getId()}' from manager.`);
@@ -977,11 +982,7 @@ export default class TranspiledModule {
977982
this.source = data.source;
978983
}
979984

980-
const loadModule = (
981-
depId: string,
982-
initiator = false,
983-
transpilation = false
984-
) => {
985+
const getModule = (depId: string) => {
985986
if (state[depId]) {
986987
return state[depId];
987988
}
@@ -990,7 +991,15 @@ export default class TranspiledModule {
990991
const query = queryParts.join(':');
991992

992993
const module = manager.transpiledModules[path].module;
993-
const tModule = manager.getTranspiledModule(module, query);
994+
return manager.getTranspiledModule(module, query);
995+
};
996+
997+
const loadModule = (
998+
depId: string,
999+
initiator = false,
1000+
transpilation = false
1001+
) => {
1002+
const tModule = getModule(depId);
9941003

9951004
if (initiator) {
9961005
if (transpilation) {

packages/app/src/sandbox/eval/transpilers/babel/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class BabelTranspiler extends WorkerTranspiler {
1717
worker: Worker;
1818

1919
constructor() {
20-
super('babel-loader', BabelWorker, 2, { hasFS: true });
20+
super('babel-loader', BabelWorker, 3, { hasFS: true });
2121
}
2222

2323
startupWorkersInitialized = false;

packages/app/src/sandbox/eval/transpilers/typescript/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class TypeScriptTranspiler extends WorkerTranspiler {
88
worker: Worker;
99

1010
constructor() {
11-
super('ts-loader', TypeScriptWorker, 2);
11+
super('ts-loader', TypeScriptWorker, 3);
1212
}
1313

1414
doTranspilation(code: string, loaderContext: LoaderContext) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import BabelWorker from 'worker-loader?publicPath=/&name=babel-transpiler.[hash:8].worker.js!./eval/transpilers/babel/worker/index.js';
22

33
window.babelworkers = [];
4-
for (let i = 0; i < 2; i++) {
4+
for (let i = 0; i < 3; i++) {
55
window.babelworkers.push(new BabelWorker());
66
}

0 commit comments

Comments
 (0)