Merge pull request #8043 from RubenVerborgh/externals-object-array

Allow array as value in externals object
This commit is contained in:
Tobias Koppers 2018-09-18 09:42:43 +02:00 committed by GitHub
commit ab284977c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 312 deletions

View File

@ -74,7 +74,9 @@ class ExternalModule extends Module {
.slice(1)
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `module.exports = require(${moduleName})${objectLookup};`;
return `module.exports = require(${JSON.stringify(
moduleName
)})${objectLookup};`;
}
checkExternalVariable(variableToCheck, request) {
@ -94,15 +96,25 @@ class ExternalModule extends Module {
}
getSourceForDefaultCase(optional, request) {
if (!Array.isArray(request)) {
// make it an array as the look up works the same basically
request = [request];
}
const variableName = request[0];
const missingModuleError = optional
? this.checkExternalVariable(request, request)
? this.checkExternalVariable(variableName, request.join("."))
: "";
return `${missingModuleError}module.exports = ${request};`;
const objectLookup = request
.slice(1)
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `${missingModuleError}module.exports = ${variableName}${objectLookup};`;
}
getSourceString(runtime) {
const request =
typeof this.request === "object"
typeof this.request === "object" && !Array.isArray(this.request)
? this.request[this.externalType]
: this.request;
switch (this.externalType) {

View File

@ -123,6 +123,9 @@
{
"type": "object"
},
{
"$ref": "#/definitions/common.arrayOfStringValues"
},
{
"type": "boolean"
}

View File

@ -1,308 +0,0 @@
/* globals describe, it, beforeEach */
"use strict";
const ExternalModule = require("../lib/ExternalModule");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
describe("ExternalModule", () => {
let externalModule;
let request;
let type;
beforeEach(() => {
request = "some/request";
type = "some-type";
externalModule = new ExternalModule(request, type, `${type} ${request}`);
});
describe("#identifier", () => {
it("returns an identifier for this module", () => {
const expected = `external "${request}"`;
expect(externalModule.identifier()).toBe(expected);
});
});
describe("#readableIdentifier", () => {
it("returns an identifier for this module", () => {
const expected = `external "${request}"`;
expect(externalModule.identifier()).toBe(expected);
});
});
describe("#needRebuild", () => {
it("always returns false", () => {
expect(externalModule.needRebuild()).toBe(false);
});
});
describe("#size", () => {
it("always returns 42", () => {
expect(externalModule.size()).toBe(42);
});
});
describe("#source", () => {
it("calls getSource with the result of getSourceString", () => {
// set up
const expectedString = "something expected stringy";
const expectedSource = "something expected source";
externalModule.getSource = jest.fn(() => expectedSource);
externalModule.getSourceString = jest.fn(() => expectedString);
// invoke
const result = externalModule.source();
// check
expect(externalModule.getSource.mock.calls.length).toBe(1);
expect(externalModule.getSourceString.mock.calls.length).toBe(1);
expect(externalModule.getSource.mock.calls[0][0]).toBe(expectedString);
expect(result).toEqual(expectedSource);
});
});
describe("#getSource", () => {
describe("given it should use source maps", () => {
beforeEach(() => {
externalModule.useSourceMap = true;
});
it("returns an instance of OriginalSource", () => {
// set up
const someSourceString = "some source string";
// invoke
const result = externalModule.getSource(someSourceString);
// check
expect(result).toBeInstanceOf(OriginalSource);
});
});
describe("given it does not use source maps", () => {
beforeEach(() => {
externalModule.useSourceMap = false;
});
it("returns an instance of RawSource", () => {
// set up
const someSourceString = "some source string";
// invoke
const result = externalModule.getSource(someSourceString);
// check
expect(result).toBeInstanceOf(RawSource);
});
});
});
describe("#getSourceForGlobalVariableExternal", () => {
describe("given an array as variable name in the global namespace", () => {
it("use the array as lookup in the global object", () => {
// set up
const type = "window";
const varName = ["foo", "bar"];
const expected =
'(function() { module.exports = window["foo"]["bar"]; }());';
// invoke
const result = externalModule.getSourceForGlobalVariableExternal(
varName,
type
);
// check
expect(result).toEqual(expected);
});
});
describe("given an single variable name", () => {
it("look it up in the global namespace", () => {
// set up
const type = "window";
const varName = "foo";
const expected = '(function() { module.exports = window["foo"]; }());';
// invoke
const result = externalModule.getSourceForGlobalVariableExternal(
varName,
type
);
// check
expect(result).toEqual(expected);
});
});
});
describe("#getSourceForCommonJsExternal", () => {
describe("given an array as names in the global namespace", () => {
it("use the first to require a module and the rest as lookup on the required module", () => {
// set up
const varName = ["module", "look", "up"];
const expected = 'module.exports = require(module)["look"]["up"];';
// invoke
const result = externalModule.getSourceForCommonJsExternal(
varName,
type
);
// check
expect(result).toEqual(expected);
});
});
describe("given an single variable name", () => {
it("require a module with that name", () => {
// set up
const type = "window";
const varName = "foo";
const expected = 'module.exports = require("foo");';
// invoke
const result = externalModule.getSourceForCommonJsExternal(
varName,
type
);
// check
expect(result).toEqual(expected);
});
});
});
describe("#checkExternalVariable", () => {
it("creates a check that fails if a variable does not exist", () => {
// set up
const variableToCheck = "foo";
const request = "bar";
const expected = `if(typeof foo === 'undefined') {var e = new Error("Cannot find module 'bar'"); e.code = 'MODULE_NOT_FOUND'; throw e;}
`;
// invoke
const result = externalModule.checkExternalVariable(
variableToCheck,
request
);
// check
expect(result).toEqual(expected);
});
});
describe("#getSourceForAmdOrUmdExternal", () => {
it("looks up a global variable as specified by the id", () => {
// set up
const id = "someId";
const optional = false;
const expected = "module.exports = __WEBPACK_EXTERNAL_MODULE_someId__;";
// invoke
const result = externalModule.getSourceForAmdOrUmdExternal(
id,
optional,
request
);
// check
expect(result).toEqual(expected);
});
describe("given an optional check is set", function() {
it("ads a check for the existence of the variable before looking it up", () => {
// set up
const id = "someId";
const optional = true;
const expected = `if(typeof __WEBPACK_EXTERNAL_MODULE_someId__ === 'undefined') {var e = new Error("Cannot find module 'some/request'"); e.code = 'MODULE_NOT_FOUND'; throw e;}
module.exports = __WEBPACK_EXTERNAL_MODULE_someId__;`;
// invoke
const result = externalModule.getSourceForAmdOrUmdExternal(
id,
optional,
request
);
// check
expect(result).toEqual(expected);
});
});
});
describe("#getSourceForDefaultCase", () => {
it("returns the given request as lookup", () => {
// set up
const optional = false;
const expected = "module.exports = some/request;";
// invoke
const result = externalModule.getSourceForDefaultCase(optional, request);
// check
expect(result).toEqual(expected);
});
describe("given an optional check is requested", function() {
it("checks for the existence of the request setting it", () => {
// set up
const optional = true;
const expected = `if(typeof some/request === 'undefined') {var e = new Error("Cannot find module 'some/request'"); e.code = 'MODULE_NOT_FOUND'; throw e;}
module.exports = some/request;`;
// invoke
const result = externalModule.getSourceForDefaultCase(
optional,
request
);
// check
expect(result).toEqual(expected);
});
});
});
describe("#updateHash", () => {
let hashedText;
let hash;
beforeEach(() => {
hashedText = "";
hash = {
update: text => {
hashedText += text;
}
};
externalModule.id = 12345678;
externalModule.updateHash(hash);
});
it("updates hash with request", () => {
expect(hashedText).toMatch("some/request");
});
it("updates hash with type", () => {
expect(hashedText).toMatch("some-type");
});
it("updates hash with module id", () => {
expect(hashedText).toMatch("12345678");
});
});
describe("#updateHash without optional", () => {
let hashedText;
let hash;
beforeEach(() => {
hashedText = "";
hash = {
update: text => {
hashedText += text;
}
};
// Note no set of `externalModule.optional`, which crashed externals in 3.7.0
externalModule.id = 12345678;
externalModule.updateHash(hash);
});
it("updates hash with request", () => {
expect(hashedText).toMatch("some/request");
});
it("updates hash with type", () => {
expect(hashedText).toMatch("some-type");
});
it("updates hash with optional flag", () => {
expect(hashedText).toMatch("false");
});
it("updates hash with module id", () => {
expect(hashedText).toMatch("12345678");
});
});
});

View File

@ -0,0 +1,4 @@
it("should not fail on optional externals", function() {
const external = require("external");
expect(external).toBe(EXPECTED);
});

View File

@ -0,0 +1,26 @@
const webpack = require("../../../../");
module.exports = [
{
output: {
libraryTarget: "commonjs2"
},
externals: {
external: ["webpack", "version"]
},
plugins: [
new webpack.DefinePlugin({
EXPECTED: JSON.stringify(webpack.version)
})
]
},
{
externals: {
external: ["Array", "isArray"]
},
plugins: [
new webpack.DefinePlugin({
EXPECTED: "Array.isArray"
})
]
}
];