mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Support meteor.nodeModules.recompile package.json configuration option.
Example:
"meteor": {
"mainModule": ...,
"testModule": ...,
"nodeModules": {
"recompile": {
"very-modern-package": ["client", "server"],
"alternate-notation-for-client-and-server": true,
"somewhat-modern-package": "legacy",
"another-package": ["legacy", "server"]
}
}
}
The keys of the meteor.nodeModules.recompile configuration object are npm
package names, and the values specify for which bundles those packages
should be recompiled using the Meteor compiler plugins system, as if the
packages were part of the Meteor application.
For example, if an npm package uses const/let syntax or arrow functions,
that's fine for modern and server code, but you would probably want to
recompile the package when building the legacy bundle. To accomplish this,
specify "legacy" or ["legacy"] as the value of the package's property,
similar to somewhat-modern-package above. These strings and arrays of
strings have the same meaning as the second argument to
api.addFiles(files, where) in a package.js file.
This configuration serves pretty much the same purpose as symlinking an
application directory into node_modules, but without any symlinking:
https://forums.meteor.com/t/litelement-import-litelement-html/45042/8?u=benjamn
The meteor.nodeModules.recompile configuration currently applies to the
application node_modules directory only (not to Npm.depends dependencies
in Meteor packages). Recompiled packages must be direct dependencies of
the application.
This commit is contained in:
@@ -860,6 +860,9 @@ _.extend(PackageSource.prototype, {
|
||||
const testModulesByArch =
|
||||
projectContext.meteorConfig.getTestModulesByArch();
|
||||
|
||||
const nodeModulesToRecompileByArch =
|
||||
projectContext.meteorConfig.getNodeModulesToRecompileByArch();
|
||||
|
||||
projectWatchSet.merge(projectContext.meteorConfig.watchSet);
|
||||
|
||||
_.each(compiler.ALL_ARCHES, function (arch) {
|
||||
@@ -871,10 +874,13 @@ _.extend(PackageSource.prototype, {
|
||||
}
|
||||
|
||||
const mainModule = projectContext.meteorConfig
|
||||
.getMainModuleForArch(arch, mainModulesByArch);
|
||||
.getMainModule(arch, mainModulesByArch);
|
||||
|
||||
const testModule = projectContext.meteorConfig
|
||||
.getTestModuleForArch(arch, testModulesByArch);
|
||||
.getTestModule(arch, testModulesByArch);
|
||||
|
||||
const nodeModulesToRecompile = projectContext.meteorConfig
|
||||
.getNodeModulesToRecompile(arch, nodeModulesToRecompileByArch);
|
||||
|
||||
// XXX what about /web.browser/* etc, these directories could also
|
||||
// be for specific client targets.
|
||||
@@ -895,6 +901,7 @@ _.extend(PackageSource.prototype, {
|
||||
ignoreFiles,
|
||||
isApp: true,
|
||||
testModule,
|
||||
nodeModulesToRecompile,
|
||||
};
|
||||
|
||||
// If this architecture has a mainModule defined in
|
||||
@@ -1094,6 +1101,7 @@ _.extend(PackageSource.prototype, {
|
||||
isApp,
|
||||
sourceArch,
|
||||
testModule,
|
||||
nodeModulesToRecompile = new Set,
|
||||
loopChecker = new SymlinkLoopChecker(this.sourceRoot),
|
||||
ignoreFiles = []
|
||||
}) {
|
||||
@@ -1254,7 +1262,7 @@ _.extend(PackageSource.prototype, {
|
||||
|
||||
// If we're in a node_modules directory, cache the results of the
|
||||
// find function for the duration of the process.
|
||||
const cacheKey = inNodeModules && makeCacheKey(dir);
|
||||
let cacheKey = inNodeModules && makeCacheKey(dir);
|
||||
if (cacheKey &&
|
||||
cacheKey in self._findSourcesCache) {
|
||||
return self._findSourcesCache[cacheKey];
|
||||
@@ -1273,14 +1281,22 @@ _.extend(PackageSource.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
const pkgJson = optimisticLookupPackageJson(self.sourceRoot, dir);
|
||||
const hasModuleEntryPoint = pkgJson && (
|
||||
isWeb ? typeof pkgJson.module === "string" : pkgJson.type === "module"
|
||||
);
|
||||
let readOptions = sourceReadOptions;
|
||||
if (inNodeModules) {
|
||||
const pkgJson = optimisticLookupPackageJson(self.sourceRoot, dir);
|
||||
const shouldRecompile =
|
||||
pkgJson && nodeModulesToRecompile.has(pkgJson.name);
|
||||
const hasModuleEntryPoint = pkgJson && (
|
||||
typeof pkgJson.module === "string" || pkgJson.type === "module"
|
||||
);
|
||||
|
||||
const readOptions = inNodeModules && !hasModuleEntryPoint
|
||||
? nodeModulesReadOptions
|
||||
: sourceReadOptions;
|
||||
if (hasModuleEntryPoint || shouldRecompile) {
|
||||
// Avoid caching node_modules code recompiled by Meteor.
|
||||
cacheKey = false;
|
||||
} else {
|
||||
readOptions = nodeModulesReadOptions;
|
||||
}
|
||||
}
|
||||
|
||||
const sources = _.difference(
|
||||
self._readAndWatchDirectory(dir, watchSet, readOptions),
|
||||
|
||||
@@ -1649,9 +1649,47 @@ export class MeteorConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// Call this first if you plan to call getMainModuleForArch multiple
|
||||
getNodeModulesToRecompileByArch() {
|
||||
const packageNamesByArch = Object.create(null);
|
||||
const recompile = this.get("nodeModules", "recompile");
|
||||
|
||||
if (recompile && typeof recompile === "object") {
|
||||
const get = arch => packageNamesByArch[arch] || (
|
||||
packageNamesByArch[arch] = new Set);
|
||||
|
||||
Object.keys(recompile).forEach(packageName => {
|
||||
const info = recompile[packageName];
|
||||
if (! info) return;
|
||||
if (info === true) {
|
||||
get("web").add(packageName);
|
||||
get("os").add(packageName);
|
||||
} else if (typeof info === "string") {
|
||||
mapWhereToArches(info).forEach(arch => {
|
||||
get(arch).add(packageName);
|
||||
});
|
||||
} else if (Array.isArray(info)) {
|
||||
info.forEach(where => {
|
||||
mapWhereToArches(where).forEach(arch => {
|
||||
get(arch).add(packageName);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return packageNamesByArch;
|
||||
}
|
||||
|
||||
getNodeModulesToRecompile(
|
||||
arch,
|
||||
packageNamesByArch = this.getNodeModulesToRecompileByArch(),
|
||||
) {
|
||||
return packageNamesByArch[arch];
|
||||
}
|
||||
|
||||
// Call this first if you plan to call getMainModule multiple
|
||||
// times, so that you can avoid repeating this work each time.
|
||||
getMainModulesByArch(arch) {
|
||||
getMainModulesByArch() {
|
||||
return this._getEntryModulesByArch("mainModule");
|
||||
}
|
||||
|
||||
@@ -1659,24 +1697,24 @@ export class MeteorConfig {
|
||||
// that architecture. For example, if this.config.mainModule.client is
|
||||
// defined, then because mapWhereToArch("client") === "web", and "web"
|
||||
// matches web.browser, return this.config.mainModule.client.
|
||||
getMainModuleForArch(
|
||||
getMainModule(
|
||||
arch,
|
||||
mainModulesByArch = this.getMainModulesByArch(),
|
||||
) {
|
||||
return this._getEntryModuleForArch(arch, mainModulesByArch);
|
||||
return this._getEntryModule(arch, mainModulesByArch);
|
||||
}
|
||||
|
||||
// Analogous to getMainModulesByArch, except for this.config.testModule.
|
||||
getTestModulesByArch(arch) {
|
||||
getTestModulesByArch() {
|
||||
return this._getEntryModulesByArch("testModule");
|
||||
}
|
||||
|
||||
// Analogous to getMainModuleForArch, except for this.config.testModule.
|
||||
getTestModuleForArch(
|
||||
// Analogous to getMainModule, except for this.config.testModule.
|
||||
getTestModule(
|
||||
arch,
|
||||
testModulesByArch = this.getTestModulesByArch(),
|
||||
) {
|
||||
return this._getEntryModuleForArch(arch, testModulesByArch);
|
||||
return this._getEntryModule(arch, testModulesByArch);
|
||||
}
|
||||
|
||||
_getEntryModulesByArch(...keys) {
|
||||
@@ -1703,7 +1741,7 @@ export class MeteorConfig {
|
||||
return entryModulesByArch;
|
||||
}
|
||||
|
||||
_getEntryModuleForArch(
|
||||
_getEntryModule(
|
||||
arch,
|
||||
entryModulesByArch,
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user