Merge pull request #11095 from vankop/support-url-requests
Support url requests
This commit is contained in:
commit
1bb02df61e
|
@ -1059,6 +1059,10 @@ export interface RuleSetRule {
|
|||
* Match the resource path of the module.
|
||||
*/
|
||||
resource?: RuleSetConditionOrConditionsAbsolute;
|
||||
/**
|
||||
* Match the resource fragment of the module.
|
||||
*/
|
||||
resourceFragment?: RuleSetConditionOrConditions;
|
||||
/**
|
||||
* Match the resource query of the module.
|
||||
*/
|
||||
|
|
|
@ -875,7 +875,8 @@ class Compiler {
|
|||
context: this.options.context,
|
||||
fs: this.inputFileSystem,
|
||||
resolverFactory: this.resolverFactory,
|
||||
options: this.options.module || {}
|
||||
options: this.options.module || {},
|
||||
associatedObjectForCache: this.root
|
||||
});
|
||||
this.hooks.normalModuleFactory.call(normalModuleFactory);
|
||||
return normalModuleFactory;
|
||||
|
|
|
@ -8,14 +8,10 @@
|
|||
const CachedConstDependency = require("./dependencies/CachedConstDependency");
|
||||
const ConstDependency = require("./dependencies/ConstDependency");
|
||||
const { evaluateToString } = require("./javascript/JavascriptParserHelpers");
|
||||
const { parseResource } = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
||||
const getQuery = request => {
|
||||
const i = request.indexOf("?");
|
||||
return i !== -1 ? request.substr(i) : "";
|
||||
};
|
||||
|
||||
const collectDeclaration = (declarations, pattern) => {
|
||||
const stack = [pattern];
|
||||
while (stack.length > 0) {
|
||||
|
@ -117,6 +113,7 @@ class ConstPlugin {
|
|||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const cacheParseResource = parseResource.bindCache(compiler.root);
|
||||
compiler.hooks.compilation.tap(
|
||||
"ConstPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
|
@ -327,9 +324,9 @@ class ConstPlugin {
|
|||
.tap("ConstPlugin", expr => {
|
||||
if (parser.scope.isAsmJs) return;
|
||||
if (!parser.state.module) return;
|
||||
return evaluateToString(getQuery(parser.state.module.resource))(
|
||||
expr
|
||||
);
|
||||
return evaluateToString(
|
||||
cacheParseResource(parser.state.module.resource).query
|
||||
)(expr);
|
||||
});
|
||||
parser.hooks.expression
|
||||
.for("__resourceQuery")
|
||||
|
@ -337,7 +334,9 @@ class ConstPlugin {
|
|||
if (parser.scope.isAsmJs) return;
|
||||
if (!parser.state.module) return;
|
||||
const dep = new CachedConstDependency(
|
||||
JSON.stringify(getQuery(parser.state.module.resource)),
|
||||
JSON.stringify(
|
||||
cacheParseResource(parser.state.module.resource).query
|
||||
),
|
||||
expr.range,
|
||||
"__resourceQuery"
|
||||
);
|
||||
|
@ -345,6 +344,32 @@ class ConstPlugin {
|
|||
parser.state.module.addPresentationalDependency(dep);
|
||||
return true;
|
||||
});
|
||||
|
||||
parser.hooks.evaluateIdentifier
|
||||
.for("__resourceFragment")
|
||||
.tap("ConstPlugin", expr => {
|
||||
if (parser.scope.isAsmJs) return;
|
||||
if (!parser.state.module) return;
|
||||
return evaluateToString(
|
||||
cacheParseResource(parser.state.module.resource).fragment
|
||||
)(expr);
|
||||
});
|
||||
parser.hooks.expression
|
||||
.for("__resourceFragment")
|
||||
.tap("ConstPlugin", expr => {
|
||||
if (parser.scope.isAsmJs) return;
|
||||
if (!parser.state.module) return;
|
||||
const dep = new CachedConstDependency(
|
||||
JSON.stringify(
|
||||
cacheParseResource(parser.state.module.resource).fragment
|
||||
),
|
||||
expr.range,
|
||||
"__resourceFragment"
|
||||
);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addPresentationalDependency(dep);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser
|
||||
|
|
|
@ -19,7 +19,7 @@ const {
|
|||
keepOriginalOrder
|
||||
} = require("./util/comparators");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
const { contextify } = require("./util/identifier");
|
||||
const { contextify, parseResource } = require("./util/identifier");
|
||||
const makeSerializable = require("./util/makeSerializable");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
|
@ -60,6 +60,7 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
* @typedef {Object} ContextModuleOptionsExtras
|
||||
* @property {string} resource
|
||||
* @property {string=} resourceQuery
|
||||
* @property {string=} resourceFragment
|
||||
* @property {TODO} resolveOptions
|
||||
*/
|
||||
|
||||
|
@ -86,21 +87,10 @@ class ContextModule extends Module {
|
|||
* @param {ContextModuleOptions} options options object
|
||||
*/
|
||||
constructor(resolveDependencies, options) {
|
||||
let resource;
|
||||
let resourceQuery;
|
||||
if (options.resourceQuery) {
|
||||
resource = options.resource;
|
||||
resourceQuery = options.resourceQuery;
|
||||
} else {
|
||||
const queryIdx = options.resource.indexOf("?");
|
||||
if (queryIdx >= 0) {
|
||||
resource = options.resource.substr(0, queryIdx);
|
||||
resourceQuery = options.resource.substr(queryIdx);
|
||||
} else {
|
||||
resource = options.resource;
|
||||
resourceQuery = "";
|
||||
}
|
||||
}
|
||||
const parsed = parseResource(options.resource);
|
||||
const resource = parsed.path;
|
||||
const resourceQuery = options.resourceQuery || parsed.query;
|
||||
const resourceFragment = options.resourceFragment || parsed.fragment;
|
||||
|
||||
super("javascript/dynamic", resource);
|
||||
|
||||
|
@ -108,8 +98,9 @@ class ContextModule extends Module {
|
|||
this.resolveDependencies = resolveDependencies;
|
||||
/** @type {Omit<ContextModuleOptions, "resolveOptions">} */
|
||||
this.options = {
|
||||
resource: resource,
|
||||
resourceQuery: resourceQuery,
|
||||
resource,
|
||||
resourceQuery,
|
||||
resourceFragment,
|
||||
mode: options.mode,
|
||||
recursive: options.recursive,
|
||||
addon: options.addon,
|
||||
|
@ -169,6 +160,9 @@ class ContextModule extends Module {
|
|||
if (this.options.resourceQuery) {
|
||||
identifier += `|${this.options.resourceQuery}`;
|
||||
}
|
||||
if (this.options.resourceFragment) {
|
||||
identifier += `|${this.options.resourceFragment}`;
|
||||
}
|
||||
if (this.options.mode) {
|
||||
identifier += `|${this.options.mode}`;
|
||||
}
|
||||
|
|
|
@ -232,6 +232,7 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|||
const {
|
||||
resource,
|
||||
resourceQuery,
|
||||
resourceFragment,
|
||||
recursive,
|
||||
regExp,
|
||||
include,
|
||||
|
@ -286,7 +287,7 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|||
.filter(obj => regExp.test(obj.request))
|
||||
.map(obj => {
|
||||
const dep = new ContextElementDependency(
|
||||
obj.request + resourceQuery,
|
||||
obj.request + resourceQuery + resourceFragment,
|
||||
obj.request,
|
||||
category,
|
||||
referencedExports
|
||||
|
|
|
@ -141,7 +141,7 @@ const createResolveDependenciesFromContextMap = createContextMap => {
|
|||
if (err) return callback(err);
|
||||
const dependencies = Object.keys(map).map(key => {
|
||||
return new ContextElementDependency(
|
||||
map[key] + options.resourceQuery,
|
||||
map[key] + options.resourceQuery + options.resourceFragment,
|
||||
key,
|
||||
options.category,
|
||||
options.referencedExports
|
||||
|
|
|
@ -9,7 +9,7 @@ const parseJson = require("json-parse-better-errors");
|
|||
const { getContext, runLoaders } = require("loader-runner");
|
||||
const querystring = require("querystring");
|
||||
const validateOptions = require("schema-utils");
|
||||
const { SyncHook } = require("tapable");
|
||||
const { HookMap, SyncHook, AsyncSeriesBailHook } = require("tapable");
|
||||
const {
|
||||
CachedSource,
|
||||
OriginalSource,
|
||||
|
@ -23,8 +23,9 @@ const ModuleError = require("./ModuleError");
|
|||
const ModuleParseError = require("./ModuleParseError");
|
||||
const ModuleWarning = require("./ModuleWarning");
|
||||
const RuntimeGlobals = require("./RuntimeGlobals");
|
||||
const UnhandledSchemeError = require("./UnhandledSchemeError");
|
||||
const WebpackError = require("./WebpackError");
|
||||
const { decodeDataURI } = require("./util/DataURI");
|
||||
const { getScheme } = require("./util/URLAbsoluteSpecifier");
|
||||
const {
|
||||
compareLocations,
|
||||
concatComparators,
|
||||
|
@ -125,21 +126,6 @@ const asBuffer = input => {
|
|||
return input;
|
||||
};
|
||||
|
||||
const readResourceFn = fs => {
|
||||
return (resource, callback) => {
|
||||
const decodedData = decodeDataURI(resource);
|
||||
|
||||
if (decodedData) {
|
||||
process.nextTick(() => {
|
||||
callback(null, decodedData);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fs.readFile(resource, callback);
|
||||
};
|
||||
};
|
||||
|
||||
class NonErrorEmittedError extends WebpackError {
|
||||
constructor(error) {
|
||||
super();
|
||||
|
@ -160,6 +146,7 @@ makeSerializable(
|
|||
/**
|
||||
* @typedef {Object} NormalModuleCompilationHooks
|
||||
* @property {SyncHook<[object, NormalModule]>} loader
|
||||
* @property {HookMap<AsyncSeriesBailHook<[string, NormalModule], string | Buffer>>} readResourceForScheme
|
||||
*/
|
||||
|
||||
/** @type {WeakMap<Compilation, NormalModuleCompilationHooks>} */
|
||||
|
@ -179,7 +166,10 @@ class NormalModule extends Module {
|
|||
let hooks = compilationHooksMap.get(compilation);
|
||||
if (hooks === undefined) {
|
||||
hooks = {
|
||||
loader: new SyncHook(["loaderContext", "module"])
|
||||
loader: new SyncHook(["loaderContext", "module"]),
|
||||
readResourceForScheme: new HookMap(
|
||||
() => new AsyncSeriesBailHook(["resource", "module"])
|
||||
)
|
||||
};
|
||||
compilationHooksMap.set(compilation, hooks);
|
||||
}
|
||||
|
@ -304,6 +294,7 @@ class NormalModule extends Module {
|
|||
updateCacheModule(module) {
|
||||
super.updateCacheModule(module);
|
||||
const m = /** @type {NormalModule} */ (module);
|
||||
this.binary = m.binary;
|
||||
this.request = m.request;
|
||||
this.userRequest = m.userRequest;
|
||||
this.rawRequest = m.rawRequest;
|
||||
|
@ -623,7 +614,22 @@ class NormalModule extends Module {
|
|||
resource: this.resource,
|
||||
loaders: this.loaders,
|
||||
context: loaderContext,
|
||||
readResource: readResourceFn(fs)
|
||||
readResource: (resource, callback) => {
|
||||
const scheme = getScheme(resource);
|
||||
if (scheme) {
|
||||
NormalModule.getCompilationHooks(compilation)
|
||||
.readResourceForScheme.for(scheme)
|
||||
.callAsync(resource, this, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
if (typeof result !== "string" && !result) {
|
||||
return callback(new UnhandledSchemeError(scheme, resource));
|
||||
}
|
||||
return callback(null, result);
|
||||
});
|
||||
} else {
|
||||
fs.readFile(resource, callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
(err, result) => {
|
||||
if (!result) {
|
||||
|
@ -959,9 +965,6 @@ class NormalModule extends Module {
|
|||
|
||||
serialize(context) {
|
||||
const { write } = context;
|
||||
// constructor
|
||||
write(this.type);
|
||||
write(this.resource);
|
||||
// deserialize
|
||||
write(this._source);
|
||||
write(this._sourceSizes);
|
||||
|
@ -974,11 +977,10 @@ class NormalModule extends Module {
|
|||
}
|
||||
|
||||
static deserialize(context) {
|
||||
const { read } = context;
|
||||
const obj = new NormalModule({
|
||||
type: read(),
|
||||
resource: read(),
|
||||
// will be filled by updateCacheModule
|
||||
type: "",
|
||||
resource: "",
|
||||
request: null,
|
||||
userRequest: null,
|
||||
rawRequest: null,
|
||||
|
|
|
@ -21,10 +21,11 @@ const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin");
|
|||
const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin");
|
||||
const RuleSetCompiler = require("./rules/RuleSetCompiler");
|
||||
const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin");
|
||||
const { getMimetype } = require("./util/DataURI");
|
||||
const LazySet = require("./util/LazySet");
|
||||
const { getScheme } = require("./util/URLAbsoluteSpecifier");
|
||||
const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
|
||||
const { join } = require("./util/fs");
|
||||
const { parseResource } = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("../declarations/WebpackOptions").ModuleOptions} ModuleOptions */
|
||||
/** @typedef {import("./Generator")} Generator */
|
||||
|
@ -48,6 +49,16 @@ const { join } = require("./util/fs");
|
|||
* @property {boolean} cacheable allow to use the unsafe cache
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ResourceData
|
||||
* @property {string} resource
|
||||
* @property {string} path
|
||||
* @property {string} query
|
||||
* @property {string} fragment
|
||||
*/
|
||||
|
||||
/** @typedef {ResourceData & { data: Record<string, any> }} ResourceDataWithData */
|
||||
|
||||
const EMPTY_RESOLVE_OPTIONS = {};
|
||||
|
||||
const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
|
||||
|
@ -124,6 +135,7 @@ const ruleSetCompiler = new RuleSetCompiler([
|
|||
new BasicMatcherRulePlugin("exclude", "resource", true),
|
||||
new BasicMatcherRulePlugin("resource"),
|
||||
new BasicMatcherRulePlugin("resourceQuery"),
|
||||
new BasicMatcherRulePlugin("resourceFragment"),
|
||||
new BasicMatcherRulePlugin("realResource"),
|
||||
new BasicMatcherRulePlugin("issuer"),
|
||||
new BasicMatcherRulePlugin("compiler"),
|
||||
|
@ -142,12 +154,23 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
* @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
|
||||
*/
|
||||
constructor({ context, fs, resolverFactory, options }) {
|
||||
constructor({
|
||||
context,
|
||||
fs,
|
||||
resolverFactory,
|
||||
options,
|
||||
associatedObjectForCache
|
||||
}) {
|
||||
super();
|
||||
this.hooks = Object.freeze({
|
||||
/** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
||||
resolve: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
|
||||
resolveForScheme: new HookMap(
|
||||
() => new AsyncSeriesBailHook(["resourceData", "resolveData"])
|
||||
),
|
||||
/** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
||||
factorize: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
||||
|
@ -191,6 +214,11 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
* @type {Map<string, WeakMap<Object, Generator>>}
|
||||
*/
|
||||
this.generatorCache = new Map();
|
||||
|
||||
const cacheParseResource = parseResource.bindCache(
|
||||
associatedObjectForCache
|
||||
);
|
||||
|
||||
this.hooks.factorize.tapAsync(
|
||||
{
|
||||
name: "NormalModuleFactory",
|
||||
|
@ -266,24 +294,14 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
} = data;
|
||||
|
||||
const loaderResolver = this.getResolver("loader");
|
||||
const normalResolver = this.getResolver(
|
||||
"normal",
|
||||
dependencies.length > 0
|
||||
? cachedSetProperty(
|
||||
resolveOptions || EMPTY_RESOLVE_OPTIONS,
|
||||
"dependencyType",
|
||||
dependencies[0].category
|
||||
)
|
||||
: resolveOptions
|
||||
);
|
||||
|
||||
/** @type {string} */
|
||||
let matchResource = undefined;
|
||||
/** @type {ResourceData | undefined} */
|
||||
let matchResourceData = undefined;
|
||||
/** @type {string} */
|
||||
let requestWithoutMatchResource = request;
|
||||
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
|
||||
if (matchResourceMatch) {
|
||||
matchResource = matchResourceMatch[1];
|
||||
let matchResource = matchResourceMatch[1];
|
||||
if (matchResource.charCodeAt(0) === 46) {
|
||||
// 46 === ".", 47 === "/"
|
||||
const secondChar = matchResource.charCodeAt(1);
|
||||
|
@ -295,6 +313,10 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
matchResource = join(this.fs, context, matchResource);
|
||||
}
|
||||
}
|
||||
matchResourceData = {
|
||||
resource: matchResource,
|
||||
...cacheParseResource(matchResource)
|
||||
};
|
||||
requestWithoutMatchResource = request.substr(
|
||||
matchResourceMatch[0].length
|
||||
);
|
||||
|
@ -319,11 +341,11 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
contextDependencies
|
||||
};
|
||||
|
||||
let dataURIMimetype = getMimetype(unresolvedResource);
|
||||
/** @type {ResourceDataWithData} */
|
||||
let resourceData;
|
||||
/** @type {string | undefined} */
|
||||
const scheme = getScheme(unresolvedResource);
|
||||
|
||||
/** @type {string | false} */
|
||||
let resource;
|
||||
let resourceResolveData;
|
||||
let loaders;
|
||||
|
||||
const continueCallback = needCalls(2, err => {
|
||||
|
@ -354,7 +376,7 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
return callback(e);
|
||||
}
|
||||
|
||||
if (resource === false) {
|
||||
if (!resourceData) {
|
||||
// ignored
|
||||
return callback(
|
||||
null,
|
||||
|
@ -367,26 +389,18 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
}
|
||||
|
||||
const userRequest =
|
||||
(matchResource !== undefined ? `${matchResource}!=!` : "") +
|
||||
stringifyLoadersAndResource(loaders, resource);
|
||||
|
||||
let resourcePath =
|
||||
matchResource !== undefined ? matchResource : resource;
|
||||
let resourceQuery = "";
|
||||
const queryIndex = resourcePath.indexOf("?");
|
||||
if (queryIndex >= 0) {
|
||||
resourceQuery = resourcePath.substr(queryIndex);
|
||||
resourcePath = resourcePath.substr(0, queryIndex);
|
||||
}
|
||||
(matchResourceData !== undefined
|
||||
? `${matchResourceData.resource}!=!`
|
||||
: "") +
|
||||
stringifyLoadersAndResource(loaders, resourceData.resource);
|
||||
|
||||
const resourceDataForRules = matchResourceData || resourceData;
|
||||
const result = this.ruleSet.exec({
|
||||
resource: resourcePath,
|
||||
realResource:
|
||||
matchResource !== undefined
|
||||
? resource.replace(/\?.*/, "")
|
||||
: resourcePath,
|
||||
resourceQuery,
|
||||
mimetype: dataURIMimetype,
|
||||
resource: resourceDataForRules.path,
|
||||
realResource: resourceData.path,
|
||||
resourceQuery: resourceDataForRules.query,
|
||||
resourceFragment: resourceDataForRules.fragment,
|
||||
mimetype: matchResourceData ? "" : resourceData.data.mimetype || "",
|
||||
issuer: contextInfo.issuer,
|
||||
compiler: contextInfo.compiler
|
||||
});
|
||||
|
@ -426,7 +440,7 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
return callback(err);
|
||||
}
|
||||
const allLoaders = postLoaders;
|
||||
if (matchResource === undefined) {
|
||||
if (matchResourceData === undefined) {
|
||||
for (const loader of loaders) allLoaders.push(loader);
|
||||
for (const loader of normalLoaders) allLoaders.push(loader);
|
||||
} else {
|
||||
|
@ -437,13 +451,18 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
const type = settings.type;
|
||||
const resolveOptions = settings.resolve;
|
||||
Object.assign(data.createData, {
|
||||
request: stringifyLoadersAndResource(allLoaders, resource),
|
||||
request: stringifyLoadersAndResource(
|
||||
allLoaders,
|
||||
resourceData.resource
|
||||
),
|
||||
userRequest,
|
||||
rawRequest: request,
|
||||
loaders: allLoaders,
|
||||
resource,
|
||||
matchResource,
|
||||
resourceResolveData,
|
||||
resource: resourceData.resource,
|
||||
matchResource: matchResourceData
|
||||
? matchResourceData.resource
|
||||
: undefined,
|
||||
resourceResolveData: resourceData.data,
|
||||
settings,
|
||||
type,
|
||||
parser: this.getParser(type, settings.parser),
|
||||
|
@ -500,19 +519,45 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
}
|
||||
);
|
||||
|
||||
if (
|
||||
unresolvedResource === "" ||
|
||||
unresolvedResource.charCodeAt(0) === 63
|
||||
) {
|
||||
// 63 === "?"
|
||||
resource = unresolvedResource;
|
||||
return continueCallback();
|
||||
// resource with scheme
|
||||
if (scheme) {
|
||||
resourceData = {
|
||||
resource: unresolvedResource,
|
||||
data: {},
|
||||
path: undefined,
|
||||
query: undefined,
|
||||
fragment: undefined
|
||||
};
|
||||
this.hooks.resolveForScheme
|
||||
.for(scheme)
|
||||
.callAsync(resourceData, data, err => {
|
||||
if (err) return continueCallback(err);
|
||||
continueCallback();
|
||||
});
|
||||
}
|
||||
|
||||
if (dataURIMimetype) {
|
||||
resource = unresolvedResource;
|
||||
// resource without scheme and without path
|
||||
else if (/^($|\?|#)/.test(unresolvedResource)) {
|
||||
resourceData = {
|
||||
resource: unresolvedResource,
|
||||
data: {},
|
||||
...cacheParseResource(unresolvedResource)
|
||||
};
|
||||
continueCallback();
|
||||
} else {
|
||||
}
|
||||
|
||||
// resource without scheme and with path
|
||||
else {
|
||||
const normalResolver = this.getResolver(
|
||||
"normal",
|
||||
dependencies.length > 0
|
||||
? cachedSetProperty(
|
||||
resolveOptions || EMPTY_RESOLVE_OPTIONS,
|
||||
"dependencyType",
|
||||
dependencies[0].category
|
||||
)
|
||||
: resolveOptions
|
||||
);
|
||||
normalResolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
|
@ -520,8 +565,13 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
resolveContext,
|
||||
(err, resolvedResource, resolvedResourceResolveData) => {
|
||||
if (err) return continueCallback(err);
|
||||
resource = resolvedResource;
|
||||
resourceResolveData = resolvedResourceResolveData;
|
||||
if (resolvedResource !== false) {
|
||||
resourceData = {
|
||||
resource: resolvedResource,
|
||||
data: resolvedResourceResolveData,
|
||||
...cacheParseResource(resolvedResource)
|
||||
};
|
||||
}
|
||||
continueCallback();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Ivan Kopeykin @vankop
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const WebpackError = require("./WebpackError");
|
||||
const makeSerializable = require("./util/makeSerializable");
|
||||
|
||||
class UnhandledSchemeError extends WebpackError {
|
||||
/**
|
||||
* @param {string} scheme scheme
|
||||
* @param {string} resource resource
|
||||
*/
|
||||
constructor(scheme, resource) {
|
||||
super(
|
||||
`Reading from "${resource}" is not handled by plugins (Unhandled scheme).` +
|
||||
'\nWebpack supports "data:" and "file:" URIs by default.' +
|
||||
`\nYou may need an additional plugin to handle "${scheme}:" URIs.`
|
||||
);
|
||||
this.file = resource;
|
||||
this.name = "UnhandledSchemeError";
|
||||
}
|
||||
}
|
||||
|
||||
makeSerializable(
|
||||
UnhandledSchemeError,
|
||||
"webpack/lib/UnhandledSchemeError",
|
||||
"UnhandledSchemeError"
|
||||
);
|
||||
|
||||
module.exports = UnhandledSchemeError;
|
|
@ -26,6 +26,9 @@ const TemplatedPathPlugin = require("./TemplatedPathPlugin");
|
|||
const UseStrictPlugin = require("./UseStrictPlugin");
|
||||
const WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");
|
||||
|
||||
const DataUriPlugin = require("./schemes/DataUriPlugin");
|
||||
const FileUriPlugin = require("./schemes/FileUriPlugin");
|
||||
|
||||
const ResolverCachePlugin = require("./cache/ResolverCachePlugin");
|
||||
|
||||
const CommonJsPlugin = require("./dependencies/CommonJsPlugin");
|
||||
|
@ -309,6 +312,9 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
: true
|
||||
}).apply(compiler);
|
||||
|
||||
new DataUriPlugin().apply(compiler);
|
||||
new FileUriPlugin().apply(compiler);
|
||||
|
||||
new CompatibilityPlugin().apply(compiler);
|
||||
new HarmonyModulesPlugin({
|
||||
module: options.module,
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { parseResource } = require("../util/identifier");
|
||||
|
||||
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
|
||||
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
|
||||
/** @typedef {import("./ContextDependency")} ContextDependency */
|
||||
|
@ -32,19 +34,6 @@ const splitContextFromPrefix = prefix => {
|
|||
};
|
||||
};
|
||||
|
||||
const splitQueryFromPostfix = postfix => {
|
||||
const idx = postfix.indexOf("?");
|
||||
let query = "";
|
||||
if (idx >= 0) {
|
||||
query = postfix.substr(idx);
|
||||
postfix = postfix.substr(0, idx);
|
||||
}
|
||||
return {
|
||||
postfix,
|
||||
query
|
||||
};
|
||||
};
|
||||
|
||||
// TODO Use Omit<> type for contextOptions when typescript >= 3.5
|
||||
/** @typedef {Partial<Pick<ContextDependencyOptions, Exclude<keyof ContextDependencyOptions, "resource"|"recursive"|"regExp">>>} PartialContextDependencyOptions */
|
||||
|
||||
|
@ -70,7 +59,10 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
|
|||
|
||||
const valueRange = param.range;
|
||||
const { context, prefix } = splitContextFromPrefix(prefixRaw);
|
||||
const { postfix, query } = splitQueryFromPostfix(postfixRaw);
|
||||
const { path: postfix, query, fragment } = parseResource(
|
||||
postfixRaw,
|
||||
parser
|
||||
);
|
||||
|
||||
// When there are more than two quasis, the generated RegExp can be more precise
|
||||
// We join the quasis with the expression regexp
|
||||
|
@ -81,20 +73,21 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
|
|||
.map(q => quoteMeta(q.string) + options.wrappedContextRegExp.source)
|
||||
.join("");
|
||||
|
||||
// Example: `./context/pre${e}inner${e}inner2${e}post?query`
|
||||
// Example: `./context/pre${e}inner${e}inner2${e}post?query#frag`
|
||||
// context: "./context"
|
||||
// prefix: "./pre"
|
||||
// innerQuasis: [BEE("inner"), BEE("inner2")]
|
||||
// (BEE = BasicEvaluatedExpression)
|
||||
// postfix: "post"
|
||||
// query: "?query"
|
||||
// fragment: "#frag"
|
||||
// regExp: /^\.\/pre.*inner.*inner2.*post$/
|
||||
const regExp = new RegExp(
|
||||
`^${quoteMeta(prefix)}${innerRegExp}${quoteMeta(postfix)}$`
|
||||
);
|
||||
const dep = new Dep(
|
||||
{
|
||||
request: context + query,
|
||||
request: context + query + fragment,
|
||||
recursive: options.wrappedContextRecursive,
|
||||
regExp,
|
||||
mode: "sync",
|
||||
|
@ -165,7 +158,10 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
|
|||
param.postfix && param.postfix.isString() ? param.postfix.range : null;
|
||||
const valueRange = param.range;
|
||||
const { context, prefix } = splitContextFromPrefix(prefixRaw);
|
||||
const { postfix, query } = splitQueryFromPostfix(postfixRaw);
|
||||
const { path: postfix, query, fragment } = parseResource(
|
||||
postfixRaw,
|
||||
parser
|
||||
);
|
||||
const regExp = new RegExp(
|
||||
`^${quoteMeta(prefix)}${options.wrappedContextRegExp.source}${quoteMeta(
|
||||
postfix
|
||||
|
@ -173,7 +169,7 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
|
|||
);
|
||||
const dep = new Dep(
|
||||
{
|
||||
request: context + query,
|
||||
request: context + query + fragment,
|
||||
recursive: options.wrappedContextRecursive,
|
||||
regExp,
|
||||
mode: "sync",
|
||||
|
|
11
lib/index.js
11
lib/index.js
|
@ -426,5 +426,16 @@ module.exports = mergeExports(fn, {
|
|||
get serialization() {
|
||||
return require("./util/serialization");
|
||||
}
|
||||
},
|
||||
|
||||
experiments: {
|
||||
schemes: {
|
||||
get HttpUriPlugin() {
|
||||
return require("./schemes/HttpUriPlugin");
|
||||
},
|
||||
get HttpsUriPlugin() {
|
||||
return require("./schemes/HttpsUriPlugin");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const NormalModule = require("../NormalModule");
|
||||
const { getMimetype, decodeDataURI } = require("../util/DataURI");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class DataUriPlugin {
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"DataUriPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
normalModuleFactory.hooks.resolveForScheme
|
||||
.for("data")
|
||||
.tap("DataUriPlugin", resourceData => {
|
||||
resourceData.data.mimetype = getMimetype(resourceData.resource);
|
||||
});
|
||||
NormalModule.getCompilationHooks(compilation)
|
||||
.readResourceForScheme.for("data")
|
||||
.tap("DataUriPlugin", resource => decodeDataURI(resource));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DataUriPlugin;
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { URL, fileURLToPath } = require("url");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class FileUriPlugin {
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"FileUriPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
normalModuleFactory.hooks.resolveForScheme
|
||||
.for("file")
|
||||
.tap("FileUriPlugin", resourceData => {
|
||||
const url = new URL(resourceData.resource);
|
||||
const path = fileURLToPath(url);
|
||||
const query = url.search;
|
||||
const fragment = url.hash;
|
||||
resourceData.path = path;
|
||||
resourceData.query = query;
|
||||
resourceData.fragment = fragment;
|
||||
resourceData.resource = path + query + fragment;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileUriPlugin;
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { URL } = require("url");
|
||||
const NormalModule = require("../NormalModule");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class HttpUriPlugin {
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"HttpUriPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
normalModuleFactory.hooks.resolveForScheme
|
||||
.for("http")
|
||||
.tap("HttpUriPlugin", resourceData => {
|
||||
const url = new URL(resourceData.resource);
|
||||
resourceData.path = url.origin + url.pathname;
|
||||
resourceData.query = url.search;
|
||||
resourceData.fragment = url.hash;
|
||||
return /** @type {true} */ (true);
|
||||
});
|
||||
NormalModule.getCompilationHooks(compilation)
|
||||
.readResourceForScheme.for("http")
|
||||
.tapAsync("HttpUriPlugin", (resource, module, callback) => {
|
||||
return require("http").get(new URL(resource), res => {
|
||||
if (res.statusCode !== 200) {
|
||||
res.destroy();
|
||||
return callback(
|
||||
new Error(`http request status code = ${res.statusCode}`)
|
||||
);
|
||||
}
|
||||
|
||||
const bufferArr = [];
|
||||
|
||||
res.on("data", chunk => {
|
||||
bufferArr.push(chunk);
|
||||
});
|
||||
|
||||
res.on("end", () => {
|
||||
if (!res.complete) {
|
||||
return callback(new Error("http request was terminated"));
|
||||
}
|
||||
|
||||
callback(null, Buffer.concat(bufferArr));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HttpUriPlugin;
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { URL } = require("url");
|
||||
const NormalModule = require("../NormalModule");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class HttpsUriPlugin {
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"HttpsUriPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
normalModuleFactory.hooks.resolveForScheme
|
||||
.for("https")
|
||||
.tap("HttpsUriPlugin", resourceData => {
|
||||
const url = new URL(resourceData.resource);
|
||||
resourceData.path = url.origin + url.pathname;
|
||||
resourceData.query = url.search;
|
||||
resourceData.fragment = url.hash;
|
||||
return /** @type {true} */ (true);
|
||||
});
|
||||
NormalModule.getCompilationHooks(compilation)
|
||||
.readResourceForScheme.for("https")
|
||||
.tapAsync("HttpsUriPlugin", (resource, module, callback) => {
|
||||
return require("https").get(new URL(resource), res => {
|
||||
if (res.statusCode !== 200) {
|
||||
res.destroy();
|
||||
return callback(
|
||||
new Error(`https request status code = ${res.statusCode}`)
|
||||
);
|
||||
}
|
||||
|
||||
const bufferArr = [];
|
||||
|
||||
res.on("data", chunk => {
|
||||
bufferArr.push(chunk);
|
||||
});
|
||||
|
||||
res.on("end", () => {
|
||||
if (!res.complete) {
|
||||
return callback(new Error("https request was terminated"));
|
||||
}
|
||||
|
||||
callback(null, Buffer.concat(bufferArr));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HttpsUriPlugin;
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
|
||||
// http://www.ietf.org/rfc/rfc2397.txt
|
||||
const URIRegEx = /^data:([^;,]+)?((?:;(?:[^;,]+))*?)(;base64)?,(.*)$/;
|
||||
const URIRegEx = /^data:([^;,]+)?((?:;(?:[^;,]+))*?)(;base64)?,(.*)$/i;
|
||||
|
||||
const decodeDataURI = uri => {
|
||||
const match = URIRegEx.exec(uri);
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Ivan Kopeykin @vankop
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("./fs").InputFileSystem} InputFileSystem */
|
||||
/** @typedef {(error: Error|null, result?: Buffer) => void} ErrorFirstCallback */
|
||||
|
||||
const backSlashCharCode = "\\".charCodeAt(0);
|
||||
const slashCharCode = "/".charCodeAt(0);
|
||||
const aLowerCaseCharCode = "a".charCodeAt(0);
|
||||
const zLowerCaseCharCode = "z".charCodeAt(0);
|
||||
const aUpperCaseCharCode = "A".charCodeAt(0);
|
||||
const zUpperCaseCharCode = "Z".charCodeAt(0);
|
||||
const _0CharCode = "0".charCodeAt(0);
|
||||
const _9CharCode = "9".charCodeAt(0);
|
||||
const plusCharCode = "+".charCodeAt(0);
|
||||
const hyphenCharCode = "-".charCodeAt(0);
|
||||
const colonCharCode = ":".charCodeAt(0);
|
||||
const hashCharCode = "#".charCodeAt(0);
|
||||
const queryCharCode = "?".charCodeAt(0);
|
||||
/**
|
||||
* Get scheme if specifier is an absolute URL specifier
|
||||
* e.g. Absolute specifiers like 'file:///user/webpack/index.js'
|
||||
* https://tools.ietf.org/html/rfc3986#section-3.1
|
||||
* @param {string} specifier specifier
|
||||
* @returns {string|undefined} scheme if absolute URL specifier provided
|
||||
*/
|
||||
function getScheme(specifier) {
|
||||
const start = specifier.charCodeAt(0);
|
||||
|
||||
// First char maybe only a letter
|
||||
if (
|
||||
(start < aLowerCaseCharCode || start > zLowerCaseCharCode) &&
|
||||
(start < aUpperCaseCharCode || start > zUpperCaseCharCode)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let i = 1;
|
||||
let ch = specifier.charCodeAt(i);
|
||||
|
||||
while (
|
||||
(ch >= aLowerCaseCharCode && ch <= zLowerCaseCharCode) ||
|
||||
(ch >= aUpperCaseCharCode && ch <= zUpperCaseCharCode) ||
|
||||
(ch >= _0CharCode && ch <= _9CharCode) ||
|
||||
ch === plusCharCode ||
|
||||
ch === hyphenCharCode
|
||||
) {
|
||||
if (++i === specifier.length) return undefined;
|
||||
ch = specifier.charCodeAt(i);
|
||||
}
|
||||
|
||||
// Scheme must end with colon
|
||||
if (ch !== colonCharCode) return undefined;
|
||||
|
||||
// Check for Windows absolute path
|
||||
// https://url.spec.whatwg.org/#url-miscellaneous
|
||||
if (i === 1) {
|
||||
const nextChar = i + 1 < specifier.length ? specifier.charCodeAt(i + 1) : 0;
|
||||
if (
|
||||
nextChar === 0 ||
|
||||
nextChar === backSlashCharCode ||
|
||||
nextChar === slashCharCode ||
|
||||
nextChar === hashCharCode ||
|
||||
nextChar === queryCharCode
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return specifier.slice(0, i).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} specifier specifier
|
||||
* @returns {string|null} protocol if absolute URL specifier provided
|
||||
*/
|
||||
function getProtocol(specifier) {
|
||||
const scheme = getScheme(specifier);
|
||||
return scheme === undefined ? undefined : scheme + ":";
|
||||
}
|
||||
|
||||
exports.getScheme = getScheme;
|
||||
exports.getProtocol = getProtocol;
|
|
@ -243,3 +243,62 @@ const _absolutify = (context, request) => {
|
|||
|
||||
const absolutify = makeCacheable(_absolutify);
|
||||
exports.absolutify = absolutify;
|
||||
|
||||
const PATH_QUERY_FRAGMENT_REGEXP = /^([^?#]*)(\?[^#]*)?(#.*)?$/;
|
||||
|
||||
/** @typedef {{ resource: string, path: string, query: string, fragment: string }} ParsedResource */
|
||||
|
||||
/**
|
||||
* @param {string} str the path with query and fragment
|
||||
* @returns {ParsedResource} parsed parts
|
||||
*/
|
||||
const _parseResource = str => {
|
||||
const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
|
||||
return {
|
||||
resource: str,
|
||||
path: match[1],
|
||||
query: match[2] || "",
|
||||
fragment: match[3] || ""
|
||||
};
|
||||
};
|
||||
exports.parseResource = (realFn => {
|
||||
/** @type {WeakMap<object, Map<string, ParsedResource>>} */
|
||||
const cache = new WeakMap();
|
||||
|
||||
const getCache = associatedObjectForCache => {
|
||||
const entry = cache.get(associatedObjectForCache);
|
||||
if (entry !== undefined) return entry;
|
||||
/** @type {Map<string, ParsedResource>} */
|
||||
const map = new Map();
|
||||
cache.set(associatedObjectForCache, map);
|
||||
return map;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} str the path with query and fragment
|
||||
* @param {Object=} associatedObjectForCache an object to which the cache will be attached
|
||||
* @returns {ParsedResource} parsed parts
|
||||
*/
|
||||
const fn = (str, associatedObjectForCache) => {
|
||||
if (!associatedObjectForCache) return realFn(str);
|
||||
const cache = getCache(associatedObjectForCache);
|
||||
const entry = cache.get(str);
|
||||
if (entry !== undefined) return entry;
|
||||
const result = realFn(str);
|
||||
cache.set(str, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
fn.bindCache = associatedObjectForCache => {
|
||||
const cache = getCache(associatedObjectForCache);
|
||||
return str => {
|
||||
const entry = cache.get(str);
|
||||
if (entry !== undefined) return entry;
|
||||
const result = realFn(str);
|
||||
cache.set(str, result);
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
return fn;
|
||||
})(_parseResource);
|
||||
|
|
|
@ -170,6 +170,7 @@ module.exports = {
|
|||
require("../sharing/ProvideForSharedDependency"),
|
||||
UnsupportedFeatureWarning: () => require("../UnsupportedFeatureWarning"),
|
||||
"util/LazySet": () => require("../util/LazySet"),
|
||||
UnhandledSchemeError: () => require("../UnhandledSchemeError"),
|
||||
WebpackError: () => require("../WebpackError"),
|
||||
|
||||
"util/registerExternalSerializer": () => {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.15",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^3.1.0",
|
||||
"loader-runner": "^4.0.0",
|
||||
"mime-types": "^2.1.26",
|
||||
"neo-async": "^2.6.1",
|
||||
"pkg-dir": "^4.2.0",
|
||||
|
|
|
@ -2563,6 +2563,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"resourceFragment": {
|
||||
"description": "Match the resource fragment of the module.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RuleSetConditionOrConditions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resourceQuery": {
|
||||
"description": "Match the resource query of the module.",
|
||||
"oneOf": [
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
const { getScheme, getProtocol } = require("../lib/util/URLAbsoluteSpecifier");
|
||||
|
||||
/**
|
||||
* @type {Array<{specifier: string, expected: string|undefined}>}
|
||||
*/
|
||||
const samples = [
|
||||
{
|
||||
specifier: "@babel/core",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "webpack",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "1webpack:///c:/windows/dir",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "webpack:///c:/windows/dir",
|
||||
expected: "webpack"
|
||||
},
|
||||
{
|
||||
specifier: "WEBPACK2020:///c:/windows/dir",
|
||||
expected: "webpack2020"
|
||||
},
|
||||
{
|
||||
specifier: "my-data:image/jpg;base64",
|
||||
expected: "my-data"
|
||||
},
|
||||
{
|
||||
specifier: "My+Data:image/jpg;base64",
|
||||
expected: "my+data"
|
||||
},
|
||||
{
|
||||
specifier: "mY+dATA:image/jpg;base64",
|
||||
expected: "my+data"
|
||||
},
|
||||
{
|
||||
specifier: "my-data/next:image/",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "my-data\\next:image/",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "D:\\path\\file.js",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "d:/path/file.js",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "z:#foo",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "Z:?query",
|
||||
expected: undefined
|
||||
},
|
||||
{
|
||||
specifier: "C:",
|
||||
expected: undefined
|
||||
}
|
||||
];
|
||||
|
||||
describe("getScheme", () => {
|
||||
samples.forEach(({ specifier, expected }, i) => {
|
||||
it(`should handle ${specifier}`, () => {
|
||||
expect(getScheme(specifier)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getProtocol", () => {
|
||||
samples.forEach(({ specifier, expected }, i) => {
|
||||
it(`should handle ${specifier}`, () => {
|
||||
expect(getProtocol(specifier)).toBe(
|
||||
expected ? expected + ":" : undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -60,10 +60,10 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry['bundle'] should be an non-empty array.
|
||||
-> All modules are loaded upon startup. The last one is exported."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry['bundle'] should be an non-empty array.
|
||||
-> All modules are loaded upon startup. The last one is exported."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -103,10 +103,10 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry should not contain the item 'abc' twice.
|
||||
-> All modules are loaded upon startup. The last one is exported."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry should not contain the item 'abc' twice.
|
||||
-> All modules are loaded upon startup. The last one is exported."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -119,16 +119,16 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry[0] should be a non-empty string.
|
||||
-> A module that is loaded upon startup. Only the last one is exported.
|
||||
- configuration.output.filename should be one of these:
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration.output.filename should be a non-empty string.
|
||||
* configuration.output.filename should be an instance of function."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.entry[0] should be a non-empty string.
|
||||
-> A module that is loaded upon startup. Only the last one is exported.
|
||||
- configuration.output.filename should be one of these:
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration.output.filename should be a non-empty string.
|
||||
* configuration.output.filename should be an instance of function."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -146,16 +146,16 @@ describe("Validation", () => {
|
|||
],
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration[0].entry[0] should be a non-empty string.
|
||||
-> A module that is loaded upon startup. Only the last one is exported.
|
||||
- configuration[1].output.filename should be one of these:
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration[1].output.filename should be a non-empty string.
|
||||
* configuration[1].output.filename should be an instance of function."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration[0].entry[0] should be a non-empty string.
|
||||
-> A module that is loaded upon startup. Only the last one is exported.
|
||||
- configuration[1].output.filename should be one of these:
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration[1].output.filename should be a non-empty string.
|
||||
* configuration[1].output.filename should be an instance of function."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -181,7 +181,7 @@ describe("Validation", () => {
|
|||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.module.rules[0].oneOf[0] has an unknown property 'passer'. These properties are valid:
|
||||
object { compiler?, enforce?, exclude?, generator?, include?, issuer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceQuery?, rules?, sideEffects?, test?, type?, use? }
|
||||
object { compiler?, enforce?, exclude?, generator?, include?, issuer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, sideEffects?, test?, type?, use? }
|
||||
-> A rule description with conditions and effects for modules."
|
||||
`)
|
||||
);
|
||||
|
@ -312,17 +312,17 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -333,17 +333,17 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -354,17 +354,17 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -375,17 +375,17 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.plugins[0] should be one of these:
|
||||
object { apply, … } | function
|
||||
-> Plugin of type object or instanceof Function.
|
||||
Details:
|
||||
* configuration.plugins[0] should be an object:
|
||||
object { apply, … }
|
||||
-> Plugin instance.
|
||||
* configuration.plugins[0] should be an instance of function.
|
||||
-> Function acting as plugin."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -452,18 +452,18 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization.splitChunks.cacheGroups should not be object { test, … }.
|
||||
-> Using the cacheGroup shorthand syntax with a cache group named 'test' is a potential config error
|
||||
Did you intent to define a cache group with a test instead?
|
||||
cacheGroups: {
|
||||
<name>: {
|
||||
test: ...
|
||||
}
|
||||
}.
|
||||
object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, filename?, idHint?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, priority?, reuseExistingChunk?, test?, type? } }
|
||||
-> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization.splitChunks.cacheGroups should not be object { test, … }.
|
||||
-> Using the cacheGroup shorthand syntax with a cache group named 'test' is a potential config error
|
||||
Did you intent to define a cache group with a test instead?
|
||||
cacheGroups: {
|
||||
<name>: {
|
||||
test: ...
|
||||
}
|
||||
}.
|
||||
object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, filename?, idHint?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, priority?, reuseExistingChunk?, test?, type? } }
|
||||
-> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -494,14 +494,14 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -511,14 +511,14 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -528,14 +528,14 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -545,14 +545,14 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.output.ecmaVersion should be one of these:
|
||||
2009 | number (should be >= 5 and <= 11) | number (should be >= 2015 and <= 2020)
|
||||
-> The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
|
||||
Details:
|
||||
* configuration.output.ecmaVersion should be >= 5 and <= 11.
|
||||
* configuration.output.ecmaVersion should be >= 2015 and <= 2020."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -590,11 +590,11 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.watchOptions should be an object:
|
||||
object { aggregateTimeout?, ignored?, poll?, stdin? }
|
||||
-> Options for the watcher."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.watchOptions should be an object:
|
||||
object { aggregateTimeout?, ignored?, poll?, stdin? }
|
||||
-> Options for the watcher."
|
||||
`)
|
||||
);
|
||||
|
||||
createTestCase(
|
||||
|
@ -619,12 +619,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'rules'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean module.rules?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'rules'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean module.rules?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"optimization.splitChunks",
|
||||
|
@ -633,12 +633,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'splitChunks'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean optimization.splitChunks?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'splitChunks'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean optimization.splitChunks?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"module.noParse",
|
||||
|
@ -647,12 +647,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'noParse'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean module.noParse?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration has an unknown property 'noParse'. These properties are valid:
|
||||
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, externalsType?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
|
||||
-> Options object as provided by the user.
|
||||
Did you mean module.noParse?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"opimization.moduleIds",
|
||||
|
@ -663,12 +663,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'hashedModuleIds'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.moduleIds: \\"hashed\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'hashedModuleIds'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.moduleIds: \\"hashed\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"optimization.chunkIds",
|
||||
|
@ -679,12 +679,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'namedChunks'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.chunkIds: \\"named\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'namedChunks'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.chunkIds: \\"named\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"optimization.chunk/moduleIds",
|
||||
|
@ -695,12 +695,12 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'occurrenceOrder'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.chunkIds: \\"size\\" and optimization.moduleIds: \\"size\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization has an unknown property 'occurrenceOrder'. These properties are valid:
|
||||
object { checkWasmTypes?, chunkIds?, concatenateModules?, flagIncludedChunks?, innerGraph?, mangleExports?, mangleWasmImports?, mergeDuplicateChunks?, minimize?, minimizer?, moduleIds?, noEmitOnErrors?, nodeEnv?, portableRecords?, providedExports?, removeAvailableModules?, removeEmptyChunks?, runtimeChunk?, sideEffects?, splitChunks?, usedExports? }
|
||||
-> Enables/Disables integrated optimizations.
|
||||
Did you mean optimization.chunkIds: \\"size\\" and optimization.moduleIds: \\"size\\" (BREAKING CHANGE since webpack 5)?"
|
||||
`)
|
||||
);
|
||||
createTestCase(
|
||||
"optimization.idHint",
|
||||
|
@ -713,11 +713,11 @@ describe("Validation", () => {
|
|||
},
|
||||
msg =>
|
||||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization.splitChunks has an unknown property 'automaticNamePrefix'. These properties are valid:
|
||||
object { automaticNameDelimiter?, cacheGroups?, chunks?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name? }
|
||||
-> Options object for splitting chunks into smaller chunks."
|
||||
`)
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.optimization.splitChunks has an unknown property 'automaticNamePrefix'. These properties are valid:
|
||||
object { automaticNameDelimiter?, cacheGroups?, chunks?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name? }
|
||||
-> Options object for splitting chunks into smaller chunks."
|
||||
`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -854,6 +854,25 @@ Object {
|
|||
"multiple": true,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"module-rules-resource-fragment": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Match the resource fragment of the module.",
|
||||
"multiple": true,
|
||||
"path": "module.rules[].resourceFragment",
|
||||
"type": "RegExp",
|
||||
},
|
||||
Object {
|
||||
"description": "Match the resource fragment of the module.",
|
||||
"multiple": true,
|
||||
"path": "module.rules[].resourceFragment",
|
||||
"type": "string",
|
||||
},
|
||||
],
|
||||
"description": "Match the resource fragment of the module.",
|
||||
"multiple": true,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"module-rules-resource-query": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
|
|
@ -38,3 +38,14 @@ it("should evaluate __dirname and __resourceQuery with replace and substr", func
|
|||
var result = require("./resourceQuery/index?" + __dirname);
|
||||
expect(result).toEqual("?resourceQuery");
|
||||
});
|
||||
|
||||
it("should evaluate __dirname and __resourceFragment with replace and substr", function() {
|
||||
var result = require("./resourceFragment/index#" + __dirname);
|
||||
expect(result).toEqual("#resourceFragment");
|
||||
});
|
||||
|
||||
it("should allow resourceFragment in context", function() {
|
||||
var fn = x => require(`./resourceFragment/${x}#..`);
|
||||
expect(fn("index")).toEqual("#resourceFragment");
|
||||
expect(fn("returnRF")).toBe("#..")
|
||||
});
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = require((
|
||||
__resourceFragment.substr(1) + "/resourceFragment/returnRF#XXXFragment"
|
||||
).replace(/XXX/g, "resource"));
|
|
@ -0,0 +1 @@
|
|||
module.exports = __resourceFragment;
|
|
@ -17,13 +17,13 @@ it("should import js module from base64 data-uri", function() {
|
|||
});
|
||||
|
||||
it("should require coffee module from base64 data-uri", function() {
|
||||
const mod = require('coffee-loader!data:text/javascript;charset=utf-8;base64,bW9kdWxlLmV4cG9ydHMgPQogIG51bWJlcjogNDIKICBmbjogKCkgLT4gIkhlbGxvIHdvcmxkIg==');
|
||||
const mod = require('coffee-loader!Data:text/javascript;charset=utf-8;base64,bW9kdWxlLmV4cG9ydHMgPQogIG51bWJlcjogNDIKICBmbjogKCkgLT4gIkhlbGxvIHdvcmxkIg==');
|
||||
expect(mod.number).toBe(42);
|
||||
expect(mod.fn()).toBe("Hello world");
|
||||
});
|
||||
|
||||
it("should require json module from base64 data-uri", function() {
|
||||
const mod = require('data:application/json;charset=utf-8;base64,ewogICJpdCI6ICJ3b3JrcyIsCiAgIm51bWJlciI6IDQyCn0K');
|
||||
const mod = require('DATA:application/json;charset=utf-8;base64,ewogICJpdCI6ICJ3b3JrcyIsCiAgIm51bWJlciI6IDQyCn0K');
|
||||
expect(mod.it).toBe("works");
|
||||
expect(mod.number).toBe(42);
|
||||
})
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
temp
|
|
@ -0,0 +1,7 @@
|
|||
import {val1, val2} from "./temp/index.js";
|
||||
import expected from "./src with spaces/module";
|
||||
|
||||
it("file url request should be supported", () => {
|
||||
expect(val1).toBe(expected);
|
||||
expect(val2).toBe(expected);
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export default "default"
|
|
@ -0,0 +1,38 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { pathToFileURL } = require("url");
|
||||
const file = path.resolve(
|
||||
"./test/configCases/asset-modules/file-url",
|
||||
"./temp/index.js"
|
||||
);
|
||||
|
||||
fs.mkdirSync("./test/configCases/asset-modules/file-url/temp", {
|
||||
recursive: true
|
||||
});
|
||||
fs.writeFileSync(
|
||||
file,
|
||||
`import v1 from ${JSON.stringify(
|
||||
pathToFileURL(
|
||||
path.resolve(
|
||||
"./test/configCases/asset-modules/file-url/src with spaces/module.js"
|
||||
)
|
||||
)
|
||||
)};
|
||||
import v2 from ${JSON.stringify(
|
||||
"file://localhost" +
|
||||
pathToFileURL(
|
||||
path.resolve(
|
||||
"./test/configCases/asset-modules/file-url/src with spaces/module.js"
|
||||
)
|
||||
)
|
||||
.toString()
|
||||
.slice("file://".length)
|
||||
)};
|
||||
export const val1 = v1;
|
||||
export const val2 = v2;`
|
||||
);
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
mode: "development"
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
import cssContent from "http://localhost:9990/index.css?query#fragment";
|
||||
|
||||
it("http url request should be supported", () => {
|
||||
expect(cssContent).toBe("a {}.webpack{}");
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
module.exports = content => `export default ${JSON.stringify(content + ".webpack{}")}`;
|
|
@ -0,0 +1 @@
|
|||
a {}
|
|
@ -0,0 +1,62 @@
|
|||
const http = require("http");
|
||||
const fs = require("fs");
|
||||
|
||||
/**
|
||||
* @param {number} port port
|
||||
* @returns {Promise<import("http").Server>} server instance
|
||||
*/
|
||||
function createServer(port) {
|
||||
const file = fs.readFileSync("./test/configCases/asset-modules/http-url/server/index.css").toString().trim();
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.url !== "/index.css") {
|
||||
res.statusCode = 404;
|
||||
res.end();
|
||||
} else {
|
||||
res.end(file);
|
||||
}
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
server.listen(port, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(server);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class ServerPlugin {
|
||||
/**
|
||||
* @param {number} port
|
||||
*/
|
||||
constructor(port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../../../../").Compiler} compiler
|
||||
*/
|
||||
apply(compiler) {
|
||||
const serverPromise = createServer(this.port);
|
||||
|
||||
serverPromise
|
||||
.then(server => server.unref());
|
||||
|
||||
compiler.hooks.done.tapAsync("ServerPlugin", (stats, callback) => {
|
||||
serverPromise
|
||||
.then(server => server.close(callback))
|
||||
.catch(callback)
|
||||
});
|
||||
|
||||
compiler.hooks.beforeRun.tapAsync("ServerPlugin", (compiler, callback) => {
|
||||
serverPromise
|
||||
.then(() => callback())
|
||||
.catch(callback)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ServerPlugin;
|
|
@ -0,0 +1,16 @@
|
|||
const { HttpUriPlugin } = require("../../../../").experiments.schemes;
|
||||
const ServerPlugin = require("./server");
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: "./loaders/css-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [new ServerPlugin(9990), new HttpUriPlugin()]
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
import codeOfConduct from "https://raw.githubusercontent.com/webpack/webpack/master/CODE_OF_CONDUCT.md";
|
||||
|
||||
it("https url request should be supported", () => {
|
||||
expect(codeOfConduct.includes("CODE_OF_CONDUCT")).toBeTruthy();
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
module.exports = content => `export default ${JSON.stringify(content)}`;
|
|
@ -0,0 +1,15 @@
|
|||
const { HttpsUriPlugin } = require("../../../../").experiments.schemes;
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.md$/,
|
||||
loader: "./loaders/md-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [new HttpsUriPlugin()]
|
||||
};
|
|
@ -1725,6 +1725,7 @@ declare abstract class ContextModuleFactory extends ModuleFactory {
|
|||
referencedExports?: string[][];
|
||||
resource: string;
|
||||
resourceQuery?: string;
|
||||
resourceFragment?: string;
|
||||
resolveOptions: any;
|
||||
},
|
||||
callback: (err?: Error, dependencies?: ContextElementDependency[]) => any
|
||||
|
@ -2858,6 +2859,22 @@ declare class HotModuleReplacementPlugin {
|
|||
apply(compiler: Compiler): void;
|
||||
static getParserHooks(parser: JavascriptParser): HMRJavascriptParserHooks;
|
||||
}
|
||||
declare class HttpUriPlugin {
|
||||
constructor();
|
||||
|
||||
/**
|
||||
* Apply the plugin
|
||||
*/
|
||||
apply(compiler: Compiler): void;
|
||||
}
|
||||
declare class HttpsUriPlugin {
|
||||
constructor();
|
||||
|
||||
/**
|
||||
* Apply the plugin
|
||||
*/
|
||||
apply(compiler: Compiler): void;
|
||||
}
|
||||
declare class IgnorePlugin {
|
||||
constructor(options: IgnorePluginOptions);
|
||||
options: IgnorePluginOptions;
|
||||
|
@ -4498,10 +4515,28 @@ declare class NormalModule extends Module {
|
|||
}
|
||||
declare interface NormalModuleCompilationHooks {
|
||||
loader: SyncHook<[any, NormalModule], void>;
|
||||
readResourceForScheme: HookMap<
|
||||
AsyncSeriesBailHook<[string, NormalModule], string | Buffer>
|
||||
>;
|
||||
}
|
||||
declare abstract class NormalModuleFactory extends ModuleFactory {
|
||||
hooks: Readonly<{
|
||||
resolve: AsyncSeriesBailHook<[ResolveData], any>;
|
||||
resolveForScheme: HookMap<
|
||||
AsyncSeriesBailHook<
|
||||
[
|
||||
{
|
||||
resource: string;
|
||||
path: string;
|
||||
query: string;
|
||||
fragment: string;
|
||||
data: Record<string, any>;
|
||||
},
|
||||
ResolveData
|
||||
],
|
||||
true | void
|
||||
>
|
||||
>;
|
||||
factorize: AsyncSeriesBailHook<[ResolveData], any>;
|
||||
beforeResolve: AsyncSeriesBailHook<[ResolveData], any>;
|
||||
afterResolve: AsyncSeriesBailHook<[ResolveData], any>;
|
||||
|
@ -6549,6 +6584,11 @@ declare interface RuleSetRule {
|
|||
*/
|
||||
resource?: RuleSetConditionAbsolute;
|
||||
|
||||
/**
|
||||
* Match the resource fragment of the module.
|
||||
*/
|
||||
resourceFragment?: RuleSetCondition;
|
||||
|
||||
/**
|
||||
* Match the resource query of the module.
|
||||
*/
|
||||
|
@ -8623,6 +8663,11 @@ declare namespace exports {
|
|||
export { MEASURE_START_OPERATION, MEASURE_END_OPERATION };
|
||||
}
|
||||
}
|
||||
export namespace experiments {
|
||||
export namespace schemes {
|
||||
export { HttpUriPlugin, HttpsUriPlugin };
|
||||
}
|
||||
}
|
||||
export type WebpackPluginFunction = (
|
||||
this: Compiler,
|
||||
compiler: Compiler
|
||||
|
|
|
@ -4465,10 +4465,10 @@ load-json-file@^4.0.0:
|
|||
pify "^3.0.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
loader-runner@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-3.1.0.tgz#e9440e5875f2ad2f968489cd2c7b59a4f2847fcb"
|
||||
integrity sha512-wE/bOCdTKMR2rm7Xxh+eirDOmN7Vx7hntWgiTayuFPtF8MgsFDo49SP8kkYz8IVlEBTOtR7P+XI7bE1xjo/IkA==
|
||||
loader-runner@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.0.0.tgz#02abcfd9fe6ff7a5aeb3547464746c4dc6ba333d"
|
||||
integrity sha512-Rqf48ufrr48gFjnaqss04QesoXB7VenbpFFIV/0yOKGnpbejrVlOPqTsoX42FG5goXM5Ixekcs4DqDzHOX2z7Q==
|
||||
|
||||
loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
|
||||
version "1.4.0"
|
||||
|
|
Loading…
Reference in New Issue