diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
| commit | d5f14083061f2ce6a42313188443a42e30796320 (patch) | |
| tree | cc6a9889e08b29595a76a33b9e7b4ef84866468b /node_modules/webpack/lib/NormalModuleFactory.js | |
| parent | b1a6ea021f29f182b62f9f81024a3d8ac8621b7f (diff) | |
added make browserlist(autoprefixer) work fixed
Diffstat (limited to 'node_modules/webpack/lib/NormalModuleFactory.js')
| -rw-r--r-- | node_modules/webpack/lib/NormalModuleFactory.js | 1166 |
1 files changed, 1166 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/NormalModuleFactory.js b/node_modules/webpack/lib/NormalModuleFactory.js new file mode 100644 index 00000000..a0d8b767 --- /dev/null +++ b/node_modules/webpack/lib/NormalModuleFactory.js @@ -0,0 +1,1166 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { getContext } = require("loader-runner"); +const asyncLib = require("neo-async"); +const { + AsyncSeriesBailHook, + SyncWaterfallHook, + SyncBailHook, + SyncHook, + HookMap +} = require("tapable"); +const ChunkGraph = require("./ChunkGraph"); +const Module = require("./Module"); +const ModuleFactory = require("./ModuleFactory"); +const ModuleGraph = require("./ModuleGraph"); +const { JAVASCRIPT_MODULE_TYPE_AUTO } = require("./ModuleTypeConstants"); +const NormalModule = require("./NormalModule"); +const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin"); +const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin"); +const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin"); +const RuleSetCompiler = require("./rules/RuleSetCompiler"); +const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin"); +const LazySet = require("./util/LazySet"); +const { getScheme } = require("./util/URLAbsoluteSpecifier"); +const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge"); +const { join } = require("./util/fs"); +const { + parseResource, + parseResourceWithoutFragment +} = require("./util/identifier"); + +/** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */ +/** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */ +/** @typedef {import("./Generator")} Generator */ +/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */ +/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ +/** @typedef {import("./NormalModule").NormalModuleCreateData} NormalModuleCreateData */ +/** @typedef {import("./Parser")} Parser */ +/** @typedef {import("./ResolverFactory")} ResolverFactory */ +/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */ +/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */ + +/** @typedef {Pick<RuleSetRule, 'type'|'sideEffects'|'parser'|'generator'|'resolve'|'layer'>} ModuleSettings */ +/** @typedef {Partial<NormalModuleCreateData & {settings: ModuleSettings}>} CreateData */ + +/** + * @typedef {Object} ResolveData + * @property {ModuleFactoryCreateData["contextInfo"]} contextInfo + * @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions + * @property {string} context + * @property {string} request + * @property {Record<string, any> | undefined} assertions + * @property {ModuleDependency[]} dependencies + * @property {string} dependencyType + * @property {CreateData} createData + * @property {LazySet<string>} fileDependencies + * @property {LazySet<string>} missingDependencies + * @property {LazySet<string>} contextDependencies + * @property {boolean} cacheable allow to use the unsafe cache + */ + +/** + * @typedef {Object} ResourceData + * @property {string} resource + * @property {string} path + * @property {string} query + * @property {string} fragment + * @property {string=} context + */ + +/** @typedef {ResourceData & { data: Record<string, any> }} ResourceDataWithData */ + +/** @typedef {Object} ParsedLoaderRequest + * @property {string} loader loader + * @property {string|undefined} options options + */ + +const EMPTY_RESOLVE_OPTIONS = {}; +const EMPTY_PARSER_OPTIONS = {}; +const EMPTY_GENERATOR_OPTIONS = {}; +const EMPTY_ELEMENTS = []; + +const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/; +const LEADING_DOT_EXTENSION_REGEX = /^[^.]/; + +const loaderToIdent = data => { + if (!data.options) { + return data.loader; + } + if (typeof data.options === "string") { + return data.loader + "?" + data.options; + } + if (typeof data.options !== "object") { + throw new Error("loader options must be string or object"); + } + if (data.ident) { + return data.loader + "??" + data.ident; + } + return data.loader + "?" + JSON.stringify(data.options); +}; + +const stringifyLoadersAndResource = (loaders, resource) => { + let str = ""; + for (const loader of loaders) { + str += loaderToIdent(loader) + "!"; + } + return str + resource; +}; + +const needCalls = (times, callback) => { + return err => { + if (--times === 0) { + return callback(err); + } + if (err && times > 0) { + times = NaN; + return callback(err); + } + }; +}; + +const mergeGlobalOptions = (globalOptions, type, localOptions) => { + const parts = type.split("/"); + let result; + let current = ""; + for (const part of parts) { + current = current ? `${current}/${part}` : part; + const options = globalOptions[current]; + if (typeof options === "object") { + if (result === undefined) { + result = options; + } else { + result = cachedCleverMerge(result, options); + } + } + } + if (result === undefined) { + return localOptions; + } else { + return cachedCleverMerge(result, localOptions); + } +}; + +// TODO webpack 6 remove +const deprecationChangedHookMessage = (name, hook) => { + const names = hook.taps + .map(tapped => { + return tapped.name; + }) + .join(", "); + + return ( + `NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` + + "Do not return the passed object, but modify it instead. " + + "Returning false will ignore the request and results in no module created." + ); +}; + +const ruleSetCompiler = new RuleSetCompiler([ + new BasicMatcherRulePlugin("test", "resource"), + new BasicMatcherRulePlugin("scheme"), + new BasicMatcherRulePlugin("mimetype"), + new BasicMatcherRulePlugin("dependency"), + new BasicMatcherRulePlugin("include", "resource"), + new BasicMatcherRulePlugin("exclude", "resource", true), + new BasicMatcherRulePlugin("resource"), + new BasicMatcherRulePlugin("resourceQuery"), + new BasicMatcherRulePlugin("resourceFragment"), + new BasicMatcherRulePlugin("realResource"), + new BasicMatcherRulePlugin("issuer"), + new BasicMatcherRulePlugin("compiler"), + new BasicMatcherRulePlugin("issuerLayer"), + new ObjectMatcherRulePlugin("assert", "assertions"), + new ObjectMatcherRulePlugin("descriptionData"), + new BasicEffectRulePlugin("type"), + new BasicEffectRulePlugin("sideEffects"), + new BasicEffectRulePlugin("parser"), + new BasicEffectRulePlugin("resolve"), + new BasicEffectRulePlugin("generator"), + new BasicEffectRulePlugin("layer"), + new UseEffectRulePlugin() +]); + +class NormalModuleFactory extends ModuleFactory { + /** + * @param {Object} param params + * @param {string=} param.context context + * @param {InputFileSystem} param.fs file system + * @param {ResolverFactory} param.resolverFactory resolverFactory + * @param {ModuleOptions} param.options options + * @param {Object=} param.associatedObjectForCache an object to which the cache will be attached + * @param {boolean=} param.layers enable layers + */ + constructor({ + context, + fs, + resolverFactory, + options, + associatedObjectForCache, + layers = false + }) { + super(); + this.hooks = Object.freeze({ + /** @type {AsyncSeriesBailHook<[ResolveData], Module | false | void>} */ + resolve: new AsyncSeriesBailHook(["resolveData"]), + /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */ + resolveForScheme: new HookMap( + () => new AsyncSeriesBailHook(["resourceData", "resolveData"]) + ), + /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */ + resolveInScheme: new HookMap( + () => new AsyncSeriesBailHook(["resourceData", "resolveData"]) + ), + /** @type {AsyncSeriesBailHook<[ResolveData], Module>} */ + factorize: new AsyncSeriesBailHook(["resolveData"]), + /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */ + beforeResolve: new AsyncSeriesBailHook(["resolveData"]), + /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */ + afterResolve: new AsyncSeriesBailHook(["resolveData"]), + /** @type {AsyncSeriesBailHook<[ResolveData["createData"], ResolveData], Module | void>} */ + createModule: new AsyncSeriesBailHook(["createData", "resolveData"]), + /** @type {SyncWaterfallHook<[Module, ResolveData["createData"], ResolveData], Module>} */ + module: new SyncWaterfallHook(["module", "createData", "resolveData"]), + createParser: new HookMap(() => new SyncBailHook(["parserOptions"])), + parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])), + createGenerator: new HookMap( + () => new SyncBailHook(["generatorOptions"]) + ), + generator: new HookMap( + () => new SyncHook(["generator", "generatorOptions"]) + ), + createModuleClass: new HookMap( + () => new SyncBailHook(["createData", "resolveData"]) + ) + }); + this.resolverFactory = resolverFactory; + this.ruleSet = ruleSetCompiler.compile([ + { + rules: options.defaultRules + }, + { + rules: options.rules + } + ]); + this.context = context || ""; + this.fs = fs; + this._globalParserOptions = options.parser; + this._globalGeneratorOptions = options.generator; + /** @type {Map<string, WeakMap<Object, TODO>>} */ + this.parserCache = new Map(); + /** @type {Map<string, WeakMap<Object, Generator>>} */ + this.generatorCache = new Map(); + /** @type {Set<Module>} */ + this._restoredUnsafeCacheEntries = new Set(); + + const cacheParseResource = parseResource.bindCache( + associatedObjectForCache + ); + const cachedParseResourceWithoutFragment = + parseResourceWithoutFragment.bindCache(associatedObjectForCache); + this._parseResourceWithoutFragment = cachedParseResourceWithoutFragment; + + this.hooks.factorize.tapAsync( + { + name: "NormalModuleFactory", + stage: 100 + }, + (resolveData, callback) => { + this.hooks.resolve.callAsync(resolveData, (err, result) => { + if (err) return callback(err); + + // Ignored + if (result === false) return callback(); + + // direct module + if (result instanceof Module) return callback(null, result); + + if (typeof result === "object") + throw new Error( + deprecationChangedHookMessage("resolve", this.hooks.resolve) + + " Returning a Module object will result in this module used as result." + ); + + this.hooks.afterResolve.callAsync(resolveData, (err, result) => { + if (err) return callback(err); + + if (typeof result === "object") + throw new Error( + deprecationChangedHookMessage( + "afterResolve", + this.hooks.afterResolve + ) + ); + + // Ignored + if (result === false) return callback(); + + const createData = resolveData.createData; + + this.hooks.createModule.callAsync( + createData, + resolveData, + (err, createdModule) => { + if (!createdModule) { + if (!resolveData.request) { + return callback(new Error("Empty dependency (no request)")); + } + + // TODO webpack 6 make it required and move javascript/wasm/asset properties to own module + createdModule = this.hooks.createModuleClass + .for(createData.settings.type) + .call(createData, resolveData); + + if (!createdModule) { + createdModule = /** @type {Module} */ ( + new NormalModule( + /** @type {NormalModuleCreateData} */ (createData) + ) + ); + } + } + + createdModule = this.hooks.module.call( + createdModule, + createData, + resolveData + ); + + return callback(null, createdModule); + } + ); + }); + }); + } + ); + this.hooks.resolve.tapAsync( + { + name: "NormalModuleFactory", + stage: 100 + }, + (data, callback) => { + const { + contextInfo, + context, + dependencies, + dependencyType, + request, + assertions, + resolveOptions, + fileDependencies, + missingDependencies, + contextDependencies + } = data; + const loaderResolver = this.getResolver("loader"); + + /** @type {ResourceData | undefined} */ + let matchResourceData = undefined; + /** @type {string} */ + let unresolvedResource; + /** @type {ParsedLoaderRequest[]} */ + let elements; + let noPreAutoLoaders = false; + let noAutoLoaders = false; + let noPrePostAutoLoaders = false; + + const contextScheme = getScheme(context); + /** @type {string | undefined} */ + let scheme = getScheme(request); + + if (!scheme) { + /** @type {string} */ + let requestWithoutMatchResource = request; + const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request); + if (matchResourceMatch) { + let matchResource = matchResourceMatch[1]; + if (matchResource.charCodeAt(0) === 46) { + // 46 === ".", 47 === "/" + const secondChar = matchResource.charCodeAt(1); + if ( + secondChar === 47 || + (secondChar === 46 && matchResource.charCodeAt(2) === 47) + ) { + // if matchResources startsWith ../ or ./ + matchResource = join(this.fs, context, matchResource); + } + } + matchResourceData = { + resource: matchResource, + ...cacheParseResource(matchResource) + }; + requestWithoutMatchResource = request.slice( + matchResourceMatch[0].length + ); + } + + scheme = getScheme(requestWithoutMatchResource); + + if (!scheme && !contextScheme) { + const firstChar = requestWithoutMatchResource.charCodeAt(0); + const secondChar = requestWithoutMatchResource.charCodeAt(1); + noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!" + noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!" + noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!"; + const rawElements = requestWithoutMatchResource + .slice( + noPreAutoLoaders || noPrePostAutoLoaders + ? 2 + : noAutoLoaders + ? 1 + : 0 + ) + .split(/!+/); + unresolvedResource = rawElements.pop(); + elements = rawElements.map(el => { + const { path, query } = cachedParseResourceWithoutFragment(el); + return { + loader: path, + options: query ? query.slice(1) : undefined + }; + }); + scheme = getScheme(unresolvedResource); + } else { + unresolvedResource = requestWithoutMatchResource; + elements = EMPTY_ELEMENTS; + } + } else { + unresolvedResource = request; + elements = EMPTY_ELEMENTS; + } + + const resolveContext = { + fileDependencies, + missingDependencies, + contextDependencies + }; + + /** @type {ResourceDataWithData} */ + let resourceData; + + let loaders; + + const continueCallback = needCalls(2, err => { + if (err) return callback(err); + + // translate option idents + try { + for (const item of loaders) { + if (typeof item.options === "string" && item.options[0] === "?") { + const ident = item.options.slice(1); + if (ident === "[[missing ident]]") { + throw new Error( + "No ident is provided by referenced loader. " + + "When using a function for Rule.use in config you need to " + + "provide an 'ident' property for referenced loader options." + ); + } + item.options = this.ruleSet.references.get(ident); + if (item.options === undefined) { + throw new Error( + "Invalid ident is provided by referenced loader" + ); + } + item.ident = ident; + } + } + } catch (e) { + return callback(e); + } + + if (!resourceData) { + // ignored + return callback(null, dependencies[0].createIgnoredModule(context)); + } + + const userRequest = + (matchResourceData !== undefined + ? `${matchResourceData.resource}!=!` + : "") + + stringifyLoadersAndResource(loaders, resourceData.resource); + + const settings = {}; + const useLoadersPost = []; + const useLoaders = []; + const useLoadersPre = []; + + // handle .webpack[] suffix + let resource; + let match; + if ( + matchResourceData && + typeof (resource = matchResourceData.resource) === "string" && + (match = /\.webpack\[([^\]]+)\]$/.exec(resource)) + ) { + settings.type = match[1]; + matchResourceData.resource = matchResourceData.resource.slice( + 0, + -settings.type.length - 10 + ); + } else { + settings.type = JAVASCRIPT_MODULE_TYPE_AUTO; + const resourceDataForRules = matchResourceData || resourceData; + const result = this.ruleSet.exec({ + resource: resourceDataForRules.path, + realResource: resourceData.path, + resourceQuery: resourceDataForRules.query, + resourceFragment: resourceDataForRules.fragment, + scheme, + assertions, + mimetype: matchResourceData + ? "" + : resourceData.data.mimetype || "", + dependency: dependencyType, + descriptionData: matchResourceData + ? undefined + : resourceData.data.descriptionFileData, + issuer: contextInfo.issuer, + compiler: contextInfo.compiler, + issuerLayer: contextInfo.issuerLayer || "" + }); + for (const r of result) { + // https://github.com/webpack/webpack/issues/16466 + // if a request exists PrePostAutoLoaders, should disable modifying Rule.type + if (r.type === "type" && noPrePostAutoLoaders) { + continue; + } + if (r.type === "use") { + if (!noAutoLoaders && !noPrePostAutoLoaders) { + useLoaders.push(r.value); + } + } else if (r.type === "use-post") { + if (!noPrePostAutoLoaders) { + useLoadersPost.push(r.value); + } + } else if (r.type === "use-pre") { + if (!noPreAutoLoaders && !noPrePostAutoLoaders) { + useLoadersPre.push(r.value); + } + } else if ( + typeof r.value === "object" && + r.value !== null && + typeof settings[r.type] === "object" && + settings[r.type] !== null + ) { + settings[r.type] = cachedCleverMerge(settings[r.type], r.value); + } else { + settings[r.type] = r.value; + } + } + } + + let postLoaders, normalLoaders, preLoaders; + + const continueCallback = needCalls(3, err => { + if (err) { + return callback(err); + } + const allLoaders = postLoaders; + if (matchResourceData === undefined) { + for (const loader of loaders) allLoaders.push(loader); + for (const loader of normalLoaders) allLoaders.push(loader); + } else { + for (const loader of normalLoaders) allLoaders.push(loader); + for (const loader of loaders) allLoaders.push(loader); + } + for (const loader of preLoaders) allLoaders.push(loader); + let type = settings.type; + const resolveOptions = settings.resolve; + const layer = settings.layer; + if (layer !== undefined && !layers) { + return callback( + new Error( + "'Rule.layer' is only allowed when 'experiments.layers' is enabled" + ) + ); + } + try { + Object.assign(data.createData, { + layer: + layer === undefined ? contextInfo.issuerLayer || null : layer, + request: stringifyLoadersAndResource( + allLoaders, + resourceData.resource + ), + userRequest, + rawRequest: request, + loaders: allLoaders, + resource: resourceData.resource, + context: + resourceData.context || getContext(resourceData.resource), + matchResource: matchResourceData + ? matchResourceData.resource + : undefined, + resourceResolveData: resourceData.data, + settings, + type, + parser: this.getParser(type, settings.parser), + parserOptions: settings.parser, + generator: this.getGenerator(type, settings.generator), + generatorOptions: settings.generator, + resolveOptions + }); + } catch (e) { + return callback(e); + } + callback(); + }); + this.resolveRequestArray( + contextInfo, + this.context, + useLoadersPost, + loaderResolver, + resolveContext, + (err, result) => { + postLoaders = result; + continueCallback(err); + } + ); + this.resolveRequestArray( + contextInfo, + this.context, + useLoaders, + loaderResolver, + resolveContext, + (err, result) => { + normalLoaders = result; + continueCallback(err); + } + ); + this.resolveRequestArray( + contextInfo, + this.context, + useLoadersPre, + loaderResolver, + resolveContext, + (err, result) => { + preLoaders = result; + continueCallback(err); + } + ); + }); + + this.resolveRequestArray( + contextInfo, + contextScheme ? this.context : context, + elements, + loaderResolver, + resolveContext, + (err, result) => { + if (err) return continueCallback(err); + loaders = result; + continueCallback(); + } + ); + + const defaultResolve = context => { + if (/^($|\?)/.test(unresolvedResource)) { + resourceData = { + resource: unresolvedResource, + data: {}, + ...cacheParseResource(unresolvedResource) + }; + continueCallback(); + } + + // resource without scheme and with path + else { + const normalResolver = this.getResolver( + "normal", + dependencyType + ? cachedSetProperty( + resolveOptions || EMPTY_RESOLVE_OPTIONS, + "dependencyType", + dependencyType + ) + : resolveOptions + ); + this.resolveResource( + contextInfo, + context, + unresolvedResource, + normalResolver, + resolveContext, + (err, resolvedResource, resolvedResourceResolveData) => { + if (err) return continueCallback(err); + if (resolvedResource !== false) { + resourceData = { + resource: resolvedResource, + data: resolvedResourceResolveData, + ...cacheParseResource(resolvedResource) + }; + } + continueCallback(); + } + ); + } + }; + + // resource with scheme + if (scheme) { + resourceData = { + resource: unresolvedResource, + data: {}, + path: undefined, + query: undefined, + fragment: undefined, + context: undefined + }; + this.hooks.resolveForScheme + .for(scheme) + .callAsync(resourceData, data, err => { + if (err) return continueCallback(err); + continueCallback(); + }); + } + + // resource within scheme + else if (contextScheme) { + resourceData = { + resource: unresolvedResource, + data: {}, + path: undefined, + query: undefined, + fragment: undefined, + context: undefined + }; + this.hooks.resolveInScheme + .for(contextScheme) + .callAsync(resourceData, data, (err, handled) => { + if (err) return continueCallback(err); + if (!handled) return defaultResolve(this.context); + continueCallback(); + }); + } + + // resource without scheme and without path + else defaultResolve(context); + } + ); + } + + cleanupForCache() { + for (const module of this._restoredUnsafeCacheEntries) { + ChunkGraph.clearChunkGraphForModule(module); + ModuleGraph.clearModuleGraphForModule(module); + module.cleanupForCache(); + } + } + + /** + * @param {ModuleFactoryCreateData} data data object + * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback + * @returns {void} + */ + create(data, callback) { + const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies); + const context = data.context || this.context; + const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS; + const dependency = dependencies[0]; + const request = dependency.request; + const assertions = dependency.assertions; + const contextInfo = data.contextInfo; + const fileDependencies = new LazySet(); + const missingDependencies = new LazySet(); + const contextDependencies = new LazySet(); + const dependencyType = + (dependencies.length > 0 && dependencies[0].category) || ""; + /** @type {ResolveData} */ + const resolveData = { + contextInfo, + resolveOptions, + context, + request, + assertions, + dependencies, + dependencyType, + fileDependencies, + missingDependencies, + contextDependencies, + createData: {}, + cacheable: true + }; + this.hooks.beforeResolve.callAsync(resolveData, (err, result) => { + if (err) { + return callback(err, { + fileDependencies, + missingDependencies, + contextDependencies, + cacheable: false + }); + } + + // Ignored + if (result === false) { + return callback(null, { + fileDependencies, + missingDependencies, + contextDependencies, + cacheable: resolveData.cacheable + }); + } + + if (typeof result === "object") + throw new Error( + deprecationChangedHookMessage( + "beforeResolve", + this.hooks.beforeResolve + ) + ); + + this.hooks.factorize.callAsync(resolveData, (err, module) => { + if (err) { + return callback(err, { + fileDependencies, + missingDependencies, + contextDependencies, + cacheable: false + }); + } + + const factoryResult = { + module, + fileDependencies, + missingDependencies, + contextDependencies, + cacheable: resolveData.cacheable + }; + + callback(null, factoryResult); + }); + }); + } + + resolveResource( + contextInfo, + context, + unresolvedResource, + resolver, + resolveContext, + callback + ) { + resolver.resolve( + contextInfo, + context, + unresolvedResource, + resolveContext, + (err, resolvedResource, resolvedResourceResolveData) => { + if (err) { + return this._resolveResourceErrorHints( + err, + contextInfo, + context, + unresolvedResource, + resolver, + resolveContext, + (err2, hints) => { + if (err2) { + err.message += ` +A fatal error happened during resolving additional hints for this error: ${err2.message}`; + err.stack += ` + +A fatal error happened during resolving additional hints for this error: +${err2.stack}`; + return callback(err); + } + if (hints && hints.length > 0) { + err.message += ` +${hints.join("\n\n")}`; + } + + // Check if the extension is missing a leading dot (e.g. "js" instead of ".js") + let appendResolveExtensionsHint = false; + const specifiedExtensions = Array.from( + resolver.options.extensions + ); + const expectedExtensions = specifiedExtensions.map(extension => { + if (LEADING_DOT_EXTENSION_REGEX.test(extension)) { + appendResolveExtensionsHint = true; + return `.${extension}`; + } + return extension; + }); + if (appendResolveExtensionsHint) { + err.message += `\nDid you miss the leading dot in 'resolve.extensions'? Did you mean '${JSON.stringify( + expectedExtensions + )}' instead of '${JSON.stringify(specifiedExtensions)}'?`; + } + + callback(err); + } + ); + } + callback(err, resolvedResource, resolvedResourceResolveData); + } + ); + } + + _resolveResourceErrorHints( + error, + contextInfo, + context, + unresolvedResource, + resolver, + resolveContext, + callback + ) { + asyncLib.parallel( + [ + callback => { + if (!resolver.options.fullySpecified) return callback(); + resolver + .withOptions({ + fullySpecified: false + }) + .resolve( + contextInfo, + context, + unresolvedResource, + resolveContext, + (err, resolvedResource) => { + if (!err && resolvedResource) { + const resource = parseResource(resolvedResource).path.replace( + /^.*[\\/]/, + "" + ); + return callback( + null, + `Did you mean '${resource}'? +BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified +(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). +The extension in the request is mandatory for it to be fully specified. +Add the extension to the request.` + ); + } + callback(); + } + ); + }, + callback => { + if (!resolver.options.enforceExtension) return callback(); + resolver + .withOptions({ + enforceExtension: false, + extensions: [] + }) + .resolve( + contextInfo, + context, + unresolvedResource, + resolveContext, + (err, resolvedResource) => { + if (!err && resolvedResource) { + let hint = ""; + const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource); + if (match) { + const fixedRequest = unresolvedResource.replace( + /(\.[^.]+)(\?|$)/, + "$2" + ); + if (resolver.options.extensions.has(match[1])) { + hint = `Did you mean '${fixedRequest}'?`; + } else { + hint = `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`; + } + } else { + hint = `Did you mean to omit the extension or to remove 'resolve.enforceExtension'?`; + } + return callback( + null, + `The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified. +${hint} +Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?` + ); + } + callback(); + } + ); + }, + callback => { + if ( + /^\.\.?\//.test(unresolvedResource) || + resolver.options.preferRelative + ) { + return callback(); + } + resolver.resolve( + contextInfo, + context, + `./${unresolvedResource}`, + resolveContext, + (err, resolvedResource) => { + if (err || !resolvedResource) return callback(); + const moduleDirectories = resolver.options.modules + .map(m => (Array.isArray(m) ? m.join(", ") : m)) + .join(", "); + callback( + null, + `Did you mean './${unresolvedResource}'? +Requests that should resolve in the current directory need to start with './'. +Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}). +If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too.` + ); + } + ); + } + ], + (err, hints) => { + if (err) return callback(err); + callback(null, hints.filter(Boolean)); + } + ); + } + + resolveRequestArray( + contextInfo, + context, + array, + resolver, + resolveContext, + callback + ) { + if (array.length === 0) return callback(null, array); + asyncLib.map( + array, + (item, callback) => { + resolver.resolve( + contextInfo, + context, + item.loader, + resolveContext, + (err, result, resolveRequest) => { + if ( + err && + /^[^/]*$/.test(item.loader) && + !/-loader$/.test(item.loader) + ) { + return resolver.resolve( + contextInfo, + context, + item.loader + "-loader", + resolveContext, + err2 => { + if (!err2) { + err.message = + err.message + + "\n" + + "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" + + ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` + + " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed"; + } + callback(err); + } + ); + } + if (err) return callback(err); + + const parsedResult = this._parseResourceWithoutFragment(result); + + const type = /\.mjs$/i.test(parsedResult.path) + ? "module" + : /\.cjs$/i.test(parsedResult.path) + ? "commonjs" + : resolveRequest.descriptionFileData === undefined + ? undefined + : resolveRequest.descriptionFileData.type; + + const resolved = { + loader: parsedResult.path, + type, + options: + item.options === undefined + ? parsedResult.query + ? parsedResult.query.slice(1) + : undefined + : item.options, + ident: item.options === undefined ? undefined : item.ident + }; + return callback(null, resolved); + } + ); + }, + callback + ); + } + + getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) { + let cache = this.parserCache.get(type); + + if (cache === undefined) { + cache = new WeakMap(); + this.parserCache.set(type, cache); + } + + let parser = cache.get(parserOptions); + + if (parser === undefined) { + parser = this.createParser(type, parserOptions); + cache.set(parserOptions, parser); + } + + return parser; + } + + /** + * @param {string} type type + * @param {{[k: string]: any}} parserOptions parser options + * @returns {Parser} parser + */ + createParser(type, parserOptions = {}) { + parserOptions = mergeGlobalOptions( + this._globalParserOptions, + type, + parserOptions + ); + const parser = this.hooks.createParser.for(type).call(parserOptions); + if (!parser) { + throw new Error(`No parser registered for ${type}`); + } + this.hooks.parser.for(type).call(parser, parserOptions); + return parser; + } + + getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) { + let cache = this.generatorCache.get(type); + + if (cache === undefined) { + cache = new WeakMap(); + this.generatorCache.set(type, cache); + } + + let generator = cache.get(generatorOptions); + + if (generator === undefined) { + generator = this.createGenerator(type, generatorOptions); + cache.set(generatorOptions, generator); + } + + return generator; + } + + createGenerator(type, generatorOptions = {}) { + generatorOptions = mergeGlobalOptions( + this._globalGeneratorOptions, + type, + generatorOptions + ); + const generator = this.hooks.createGenerator + .for(type) + .call(generatorOptions); + if (!generator) { + throw new Error(`No generator registered for ${type}`); + } + this.hooks.generator.for(type).call(generator, generatorOptions); + return generator; + } + + getResolver(type, resolveOptions) { + return this.resolverFactory.get(type, resolveOptions); + } +} + +module.exports = NormalModuleFactory; |
