Skip to content

Commit e39c793

Browse files
authored
Fix loading angular resources from node_modules (codesandbox#3335)
1 parent 06ae1b6 commit e39c793

File tree

2 files changed

+153
-133
lines changed

2 files changed

+153
-133
lines changed

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ async function addAngularJSONResources(manager) {
9393
}
9494
}
9595

96+
const getPathFromResource = (root, p) => {
97+
const nodeModuleRegex = /(^\.\/)?node_modules\//;
98+
if (/(^\.\/)?node_modules/.test(p)) {
99+
// If starts with node_modules or ./node_modules
100+
return p.replace(nodeModuleRegex, '');
101+
}
102+
103+
return absolute(join(root || 'src', p));
104+
};
105+
96106
async function addAngularCLIResources(manager) {
97107
const { parsed } = manager.configurations['angular-cli'];
98108
if (parsed.apps && parsed.apps[0]) {
@@ -103,7 +113,7 @@ async function addAngularCLIResources(manager) {
103113
/* eslint-disable no-await-in-loop */
104114
for (let i = 0; i < styles.length; i++) {
105115
const p = styles[i];
106-
const finalPath = absolute(join(app.root || 'src', p.input || p));
116+
const finalPath = getPathFromResource(app.root, p.input || p);
107117

108118
const tModule = await manager.resolveTranspiledModuleAsync(
109119
finalPath,
@@ -118,7 +128,7 @@ async function addAngularCLIResources(manager) {
118128

119129
const scriptTModules = await Promise.all(
120130
scripts.map(async p => {
121-
const finalPath = absolute(join(app.root || 'src', p));
131+
const finalPath = getPathFromResource(app.root, p);
122132
const tModule = await manager.resolveTranspiledModuleAsync(
123133
finalPath,
124134
null

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

Lines changed: 141 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -565,160 +565,170 @@ export default class TranspiledModule {
565565
* @param {*} manager
566566
*/
567567
async transpile(manager: Manager) {
568-
if (this.source) {
569-
return this;
570-
}
568+
try {
569+
if (this.source) {
570+
return this;
571+
}
571572

572-
if (manager.transpileJobs[this.getId()]) {
573-
// Is already being transpiled
574-
return this;
575-
}
573+
if (manager.transpileJobs[this.getId()]) {
574+
// Is already being transpiled
575+
return this;
576+
}
576577

577-
// eslint-disable-next-line
578-
manager.transpileJobs[this.getId()] = true;
578+
// eslint-disable-next-line
579+
manager.transpileJobs[this.getId()] = true;
579580

580-
this.hasMissingDependencies = false;
581+
this.hasMissingDependencies = false;
581582

582-
// Remove this module from the initiators of old deps, so we can populate a
583-
// fresh cache
584-
this.dependencies.forEach(tModule => {
585-
tModule.initiators.delete(this);
586-
});
587-
this.transpilationDependencies.forEach(tModule => {
588-
tModule.transpilationInitiators.delete(this);
589-
});
590-
this.childModules.forEach(tModule => {
591-
tModule.dispose(manager);
592-
});
593-
this.dependencies.clear();
594-
this.transpilationDependencies.clear();
595-
this.childModules.length = 0;
596-
this.errors = [];
597-
this.warnings = [];
598-
599-
let code = this.module.code || '';
600-
let finalSourceMap = null;
601-
602-
const { requires } = this.module;
603-
if (requires != null && this.query === '') {
604-
// We now know that this has been transpiled on the server, so we shortcut
605-
const loaderContext = this.getLoaderContext(manager, {});
606-
// These are precomputed requires, for npm dependencies
607-
requires.forEach(r => {
608-
if (r.indexOf('glob:') === 0) {
609-
const reGlob = r.replace('glob:', '');
610-
loaderContext.addDependenciesInDirectory(reGlob);
611-
} else {
612-
loaderContext.addDependency(r);
613-
}
583+
// Remove this module from the initiators of old deps, so we can populate a
584+
// fresh cache
585+
this.dependencies.forEach(tModule => {
586+
tModule.initiators.delete(this);
587+
});
588+
this.transpilationDependencies.forEach(tModule => {
589+
tModule.transpilationInitiators.delete(this);
614590
});
591+
this.childModules.forEach(tModule => {
592+
tModule.dispose(manager);
593+
});
594+
this.dependencies.clear();
595+
this.transpilationDependencies.clear();
596+
this.childModules.length = 0;
597+
this.errors = [];
598+
this.warnings = [];
599+
600+
let code = this.module.code || '';
601+
let finalSourceMap = null;
602+
603+
const { requires } = this.module;
604+
if (requires != null && this.query === '') {
605+
// We now know that this has been transpiled on the server, so we shortcut
606+
const loaderContext = this.getLoaderContext(manager, {});
607+
// These are precomputed requires, for npm dependencies
608+
requires.forEach(r => {
609+
if (r.indexOf('glob:') === 0) {
610+
const reGlob = r.replace('glob:', '');
611+
loaderContext.addDependenciesInDirectory(reGlob);
612+
} else {
613+
loaderContext.addDependency(r);
614+
}
615+
});
615616

616-
// eslint-disable-next-line
617-
code = this.module.code;
618-
} else {
619-
const transpilers = manager.preset.getLoaders(this.module, this.query);
617+
// eslint-disable-next-line
618+
code = this.module.code;
619+
} else {
620+
const transpilers = manager.preset.getLoaders(this.module, this.query);
620621

621-
for (let i = 0; i < transpilers.length; i += 1) {
622-
const transpilerConfig = transpilers[i];
623-
const loaderContext = this.getLoaderContext(
624-
manager,
625-
transpilerConfig.options || {}
626-
);
627-
loaderContext.remainingRequests = transpilers
628-
.slice(i + 1)
629-
.map(transpiler => transpiler.transpiler.name)
630-
.concat([this.module.path])
631-
.join('!');
632-
633-
try {
634-
const startTime = Date.now();
635-
const {
636-
transpiledCode,
637-
sourceMap,
638-
} = await transpilerConfig.transpiler.transpile(code, loaderContext); // eslint-disable-line no-await-in-loop
639-
debug(`Transpiled '${this.getId()}' in ${Date.now() - startTime}ms`);
640-
641-
if (this.errors.length) {
642-
throw this.errors[0];
643-
}
622+
for (let i = 0; i < transpilers.length; i += 1) {
623+
const transpilerConfig = transpilers[i];
624+
const loaderContext = this.getLoaderContext(
625+
manager,
626+
transpilerConfig.options || {}
627+
);
628+
loaderContext.remainingRequests = transpilers
629+
.slice(i + 1)
630+
.map(transpiler => transpiler.transpiler.name)
631+
.concat([this.module.path])
632+
.join('!');
644633

645-
code = transpiledCode;
646-
finalSourceMap = sourceMap;
647-
} catch (e) {
648-
e.fileName = loaderContext.path;
649-
e.tModule = this;
650-
this.resetTranspilation();
634+
try {
635+
const startTime = Date.now();
636+
const {
637+
transpiledCode,
638+
sourceMap,
639+
// eslint-disable-next-line no-await-in-loop
640+
} = await transpilerConfig.transpiler.transpile(
641+
code,
642+
loaderContext
643+
);
644+
debug(
645+
`Transpiled '${this.getId()}' in ${Date.now() - startTime}ms`
646+
);
651647

652-
// Compilation should also be reset, since the code will be different now
653-
// we don't have a transpilation.
654-
this.resetCompilation();
655-
manager.clearCache();
648+
if (this.errors.length) {
649+
throw this.errors[0];
650+
}
651+
652+
code = transpiledCode;
653+
finalSourceMap = sourceMap;
654+
} catch (e) {
655+
e.fileName = loaderContext.path;
656+
e.tModule = this;
657+
this.resetTranspilation();
658+
659+
// Compilation should also be reset, since the code will be different now
660+
// we don't have a transpilation.
661+
this.resetCompilation();
662+
manager.clearCache();
656663

657-
throw e;
664+
throw e;
665+
}
658666
}
659-
}
660667

661-
this.logWarnings();
662-
}
668+
this.logWarnings();
669+
}
663670

664-
const sourceEqualsCompiled = code === this.module.code;
665-
const sourceURL = `//# sourceURL=${location.origin}${this.module.path}${
666-
this.query ? `?${this.hash}` : ''
667-
}`;
671+
const sourceEqualsCompiled = code === this.module.code;
672+
const sourceURL = `//# sourceURL=${location.origin}${this.module.path}${
673+
this.query ? `?${this.hash}` : ''
674+
}`;
668675

669-
// Add the source of the file by default, this is important for source mapping
670-
// errors back to their origin
671-
code = `${code}\n${sourceURL}`;
676+
// Add the source of the file by default, this is important for source mapping
677+
// errors back to their origin
678+
code = `${code}\n${sourceURL}`;
672679

673-
this.source = new ModuleSource(
674-
this.module.path,
675-
code,
676-
finalSourceMap,
677-
sourceEqualsCompiled
678-
);
680+
this.source = new ModuleSource(
681+
this.module.path,
682+
code,
683+
finalSourceMap,
684+
sourceEqualsCompiled
685+
);
679686

680-
if (
681-
this.previousSource &&
682-
this.previousSource.compiledCode !== this.source.compiledCode
683-
) {
684-
const hasHMR = manager.preset
685-
.getLoaders(this.module, this.query)
686-
.some(t =>
687-
t.transpiler.HMREnabled == null ? true : t.transpiler.HMREnabled
688-
);
687+
if (
688+
this.previousSource &&
689+
this.previousSource.compiledCode !== this.source.compiledCode
690+
) {
691+
const hasHMR = manager.preset
692+
.getLoaders(this.module, this.query)
693+
.some(t =>
694+
t.transpiler.HMREnabled == null ? true : t.transpiler.HMREnabled
695+
);
689696

690-
if (!hasHMR) {
691-
manager.markHardReload();
692-
} else {
693-
this.resetCompilation();
697+
if (!hasHMR) {
698+
manager.markHardReload();
699+
} else {
700+
this.resetCompilation();
701+
}
694702
}
695-
}
696703

697-
await Promise.all(
698-
this.asyncDependencies.map(async p => {
699-
try {
700-
const tModule = await p;
704+
await Promise.all(
705+
this.asyncDependencies.map(async p => {
706+
try {
707+
const tModule = await p;
701708

702-
this.dependencies.add(tModule);
703-
tModule.initiators.add(this);
704-
} catch (e) {
705-
/* let this handle at evaluation */
706-
}
707-
})
708-
);
709+
this.dependencies.add(tModule);
710+
tModule.initiators.add(this);
711+
} catch (e) {
712+
/* let this handle at evaluation */
713+
}
714+
})
715+
);
709716

710-
this.asyncDependencies = [];
717+
this.asyncDependencies = [];
711718

712-
await Promise.all(
713-
flattenDeep([
714-
...Array.from(this.transpilationInitiators).map(t =>
715-
t.transpile(manager)
716-
),
717-
...Array.from(this.dependencies).map(t => t.transpile(manager)),
718-
])
719-
);
719+
await Promise.all(
720+
flattenDeep([
721+
...Array.from(this.transpilationInitiators).map(t =>
722+
t.transpile(manager)
723+
),
724+
...Array.from(this.dependencies).map(t => t.transpile(manager)),
725+
])
726+
);
720727

721-
return this;
728+
return this;
729+
} finally {
730+
delete manager.transpileJobs[this.getId()];
731+
}
722732
}
723733

724734
logWarnings = () => {

0 commit comments

Comments
 (0)