Skip to content

Commit

Permalink
Verify version of node builtin
Browse files Browse the repository at this point in the history
  • Loading branch information
mischnic committed Aug 10, 2022
1 parent 9e5d055 commit 6092f6a
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 74 deletions.
5 changes: 2 additions & 3 deletions packages/resolvers/default/src/DefaultResolver.js
Expand Up @@ -25,9 +25,8 @@ export default (new Resolver({
? ['ts', 'tsx', 'js', 'jsx', 'json']
: [],
mainFields: ['source', 'browser', 'module', 'main'],
packageManager: options.shouldAutoInstall
? options.packageManager
: undefined,
packageManager: options.packageManager,
shouldAutoInstall: options.shouldAutoInstall,
logger,
});

Expand Down
109 changes: 64 additions & 45 deletions packages/utils/node-resolver-core/src/NodeResolver.js
Expand Up @@ -46,6 +46,7 @@ type Options = {|
mainFields: Array<string>,
packageManager?: PackageManager,
logger?: PluginLogger,
shouldAutoInstall?: boolean,
|};
type ResolvedFile = {|
path: string,
Expand Down Expand Up @@ -96,6 +97,7 @@ export default class NodeResolver {
packageCache: Map<string, InternalPackageJSON>;
rootPackage: InternalPackageJSON | null;
packageManager: ?PackageManager;
shouldAutoInstall: boolean;
logger: ?PluginLogger;

constructor(opts: Options) {
Expand All @@ -108,6 +110,7 @@ export default class NodeResolver {
this.packageCache = new Map();
this.rootPackage = null;
this.packageManager = opts.packageManager;
this.shouldAutoInstall = opts.shouldAutoInstall ?? false;
this.logger = opts.logger;
}

Expand Down Expand Up @@ -274,7 +277,7 @@ export default class NodeResolver {
} else if (builtin === empty) {
return {filePath: empty};
} else if (builtin !== undefined) {
filename = builtin;
filename = builtin.name;
}

if (this.shouldIncludeNodeModule(env, filename) === false) {
Expand All @@ -292,46 +295,16 @@ export default class NodeResolver {
// ignore
}

// Auto install node builtin polyfills if not already available
if (resolved === undefined && builtin != null) {
let packageName = builtin.split('/')[0];
// Auto install node builtin polyfills if not already available or check that the correct
// version is installed
if (builtin != null) {
// This assumes that there are no polyfill packages that are scoped
let packageName = builtin.name.split('/')[0];
let packageManager = this.packageManager;
if (packageManager) {
this.logger?.warn({
message: md`Auto installing polyfill for Node builtin module "${specifier}"...`,
codeFrames: [
{
filePath: ctx.loc?.filePath ?? sourceFile,
codeHighlights: ctx.loc
? [
{
message: 'used here',
start: ctx.loc.start,
end: ctx.loc.end,
},
]
: [],
},
],
documentationURL:
'https://parceljs.org/features/node-emulation/#polyfilling-%26-excluding-builtin-node-modules',
});

await packageManager.resolve(builtin, this.projectRoot + '/index', {
saveDev: true,
shouldAutoInstall: true,
});

// Re-resolve
try {
resolved = this.findNodeModulePath(filename, sourceFile, ctx);
} catch (err) {
// ignore
}
} else {
throw new ThrowableDiagnostic({
diagnostic: {
message: md`Node builtin polyfill "${packageName}" is not installed, but auto install is disabled.`,
if (resolved == null) {
if (this.shouldAutoInstall && packageManager) {
this.logger?.warn({
message: md`Auto installing polyfill for Node builtin module "${specifier}"...`,
codeFrames: [
{
filePath: ctx.loc?.filePath ?? sourceFile,
Expand All @@ -348,10 +321,53 @@ export default class NodeResolver {
],
documentationURL:
'https://parceljs.org/features/node-emulation/#polyfilling-%26-excluding-builtin-node-modules',
hints: [
md`Install the "${packageName}" package with your package manager, and run Parcel again.`,
],
},
});

await packageManager.resolve(packageName, sourceFile, {
saveDev: true,
shouldAutoInstall: true,
range: builtin.range,
});

// Re-resolve
try {
resolved = this.findNodeModulePath(filename, sourceFile, ctx);
} catch (err) {
// ignore
}
} else {
throw new ThrowableDiagnostic({
diagnostic: {
message: md`Node builtin polyfill "${packageName}" is not installed, but auto install is disabled.`,
codeFrames: [
{
filePath: ctx.loc?.filePath ?? sourceFile,
codeHighlights: ctx.loc
? [
{
message: 'used here',
start: ctx.loc.start,
end: ctx.loc.end,
},
]
: [],
},
],
documentationURL:
'https://parceljs.org/features/node-emulation/#polyfilling-%26-excluding-builtin-node-modules',
hints: [
md`Install the "${packageName}" package with your package manager, and run Parcel again.`,
],
},
});
}
} else if (builtin.range != null) {
// TODO packageManager can be null for backwards compatibility, but that could cause invalid
// resolutions in monorepos
await packageManager?.resolve(packageName, sourceFile, {
saveDev: true,
shouldAutoInstall: true,
range: builtin.range,
});
}
}
Expand Down Expand Up @@ -707,7 +723,10 @@ export default class NodeResolver {
return resolvedFile;
}

findBuiltin(filename: string, env: Environment): ?string {
findBuiltin(
filename: string,
env: Environment,
): ?{|name: string, range: ?string|} {
const isExplicitNode = filename.startsWith('node:');
if (isExplicitNode || builtins[filename]) {
if (env.isNode()) {
Expand Down
53 changes: 27 additions & 26 deletions packages/utils/node-resolver-core/src/builtins.js
Expand Up @@ -4,35 +4,36 @@ import {builtinModules} from 'module';

export const empty: string = require.resolve('./_empty.js');

// $FlowFixMe
let builtins: {[string]: any, ...} = Object.create(null);
let builtins: {[string]: {|name: string, range: ?string|}, ...} =
// $FlowFixMe
Object.create(null);
// use definite (current) list of Node builtins
for (let key of builtinModules) {
builtins[key] = empty;
builtins[key] = {name: empty, range: null};
}

builtins.assert = 'assert/';
builtins.buffer = 'buffer/';
builtins.console = 'console-browserify';
builtins.constants = 'constants-browserify';
builtins.crypto = 'crypto-browserify';
builtins.domain = 'domain-browser';
builtins.events = 'events/';
builtins.http = 'stream-http';
builtins.https = 'https-browserify';
builtins.os = 'os-browserify/browser.js';
builtins.path = 'path-browserify';
builtins.process = 'process/browser.js';
builtins.punycode = 'punycode/';
builtins.querystring = 'querystring-es3/';
builtins.stream = 'stream-browserify';
builtins.string_decoder = 'string_decoder/';
builtins.sys = 'util/util.js';
builtins.timers = 'timers-browserify';
builtins.tty = 'tty-browserify';
builtins.url = 'url/';
builtins.util = 'util/util.js';
builtins.vm = 'vm-browserify';
builtins.zlib = 'browserify-zlib';
builtins.assert = {name: 'assert/', range: '^2.0.0'};
builtins.buffer = {name: 'buffer/', range: '^5.5.0'};
builtins.console = {name: 'console-browserify', range: '^1.2.0'};
builtins.constants = {name: 'constants-browserify', range: '^1.0.0'};
builtins.crypto = {name: 'crypto-browserify', range: '^3.12.0'};
builtins.domain = {name: 'domain-browser', range: '^3.5.0'};
builtins.events = {name: 'events/', range: '^3.1.0'};
builtins.http = {name: 'stream-http', range: '^3.1.0'};
builtins.https = {name: 'https-browserify', range: '^1.0.0'};
builtins.os = {name: 'os-browserify/browser.js', range: '^0.3.0'};
builtins.path = {name: 'path-browserify', range: '^1.0.0'};
builtins.process = {name: 'process/browser.js', range: '^0.11.10'};
builtins.punycode = {name: 'punycode/', range: '^1.4.1'};
builtins.querystring = {name: 'querystring-es3/', range: '^0.2.1'};
builtins.stream = {name: 'stream-browserify', range: '^3.0.0'};
builtins.string_decoder = {name: 'string_decoder/', range: '^1.3.0'};
builtins.sys = {name: 'util/util.js', range: '^0.12.3'};
builtins.timers = {name: 'timers-browserify', range: '^2.0.11'};
builtins.tty = {name: 'tty-browserify', range: '^0.0.1'};
builtins.url = {name: 'url/', range: '^0.11.0'};
builtins.util = {name: 'util/util.js', range: '^0.12.3'};
builtins.vm = {name: 'vm-browserify', range: '^1.1.2'};
builtins.zlib = {name: 'browserify-zlib', range: '^0.2.0'};

export default builtins;

0 comments on commit 6092f6a

Please sign in to comment.