Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions resolvers/webpack/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
"import/no-extraneous-dependencies": 1,
"no-console": 1,
},
"env": {
"es6": true,
},
}
9 changes: 7 additions & 2 deletions resolvers/webpack/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel

## Unreleased

### Added
- add support for webpack5 'externals function' ([#2023], thanks [@jet2jet])

### Changed
- Add warning about async Webpack configs ([#1962], thanks [@ogonkov])
- Add warning about async Webpack configs ([#1962], thanks [@ogonkov])
- Replace node-libs-browser with is-core-module ([#1967], thanks [@andersk])

## 0.13.0 - 2020-09-27
Expand Down Expand Up @@ -141,6 +144,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
- `interpret` configs (such as `.babel.js`).
Thanks to [@gausie] for the initial PR ([#164], ages ago! 😅) and [@jquense] for tests ([#278]).

[#2023]: https://github.com/benmosher/eslint-plugin-import/pull/2023
[#1967]: https://github.com/benmosher/eslint-plugin-import/pull/1967
[#1962]: https://github.com/benmosher/eslint-plugin-import/pull/1962
[#1705]: https://github.com/benmosher/eslint-plugin-import/pull/1705
Expand Down Expand Up @@ -200,4 +204,5 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
[@migueloller]: https://github.com/migueloller
[@opichals]: https://github.com/opichals
[@andersk]: https://github.com/andersk
[@ogonkov]: https://github.com/ogonkov
[@ogonkov]: https://github.com/ogonkov
[@jet2jet]: https://github.com/jet2jet
47 changes: 40 additions & 7 deletions resolvers/webpack/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,14 @@ exports.resolve = function (source, file, settings) {

log('Using config: ', webpackConfig);

const resolveSync = getResolveSync(configPath, webpackConfig, cwd);

// externals
if (findExternal(source, webpackConfig.externals, path.dirname(file))) {
if (findExternal(source, webpackConfig.externals, path.dirname(file), resolveSync)) {
return { found: true, path: null };
}

// otherwise, resolve "normally"
const resolveSync = getResolveSync(configPath, webpackConfig, cwd);

try {
return { found: true, path: resolveSync(path.dirname(file), source) };
Expand Down Expand Up @@ -323,15 +324,15 @@ function makeRootPlugin(ModulesInRootPlugin, name, root) {
}
/* eslint-enable */

function findExternal(source, externals, context) {
function findExternal(source, externals, context, resolveSync) {
if (!externals) return false;

// string match
if (typeof externals === 'string') return (source === externals);

// array: recurse
if (Array.isArray(externals)) {
return externals.some(function (e) { return findExternal(source, e, context); });
return externals.some(function (e) { return findExternal(source, e, context, resolveSync); });
}

if (isRegex(externals)) {
Expand All @@ -340,13 +341,45 @@ function findExternal(source, externals, context) {

if (typeof externals === 'function') {
let functionExternalFound = false;
externals.call(null, context, source, function(err, value) {
const callback = function (err, value) {
if (err) {
functionExternalFound = false;
} else {
functionExternalFound = findExternal(source, value, context);
functionExternalFound = findExternal(source, value, context, resolveSync);
}
});
};
// - for prior webpack 5, 'externals function' uses 3 arguments
// - for webpack 5, the count of arguments is less than 3
if (externals.length === 3) {
externals.call(null, context, source, callback);
} else {
const ctx = {
context,
request: source,
contextInfo: {
issuer: '',
issuerLayer: null,
compiler: '',
},
getResolve: () => (resolveContext, requestToResolve, cb) => {
if (cb) {
try {
cb(null, resolveSync(resolveContext, requestToResolve));
} catch (e) {
cb(e);
}
} else {
log('getResolve without callback not supported');
return Promise.reject(new Error('Not supported'));
}
},
};
const result = externals.call(null, ctx, callback);
// todo handling Promise object (using synchronous-promise package?)
if (result && typeof result.then === 'function') {
log('Asynchronous functions for externals not supported');
}
}
return functionExternalFound;
}

Expand Down
29 changes: 29 additions & 0 deletions resolvers/webpack/test/externals.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ const webpack = require('../index');
const file = path.join(__dirname, 'files', 'dummy.js');

describe('externals', function () {
const settingsWebpack5 = {
config: require(path.join(__dirname, './files/webpack.config.webpack5.js')),
};
const settingsWebpack5Async = {
config: require(path.join(__dirname, './files/webpack.config.webpack5.async-externals.js')),
};

it('works on just a string', function () {
const resolved = webpack.resolve('bootstrap', file);
expect(resolved).to.have.property('found', true);
Expand All @@ -32,4 +39,26 @@ describe('externals', function () {
expect(resolved).to.have.property('found', true);
expect(resolved).to.have.property('path', null);
});

it('works on a function (synchronous) for webpack 5', function () {
const resolved = webpack.resolve('underscore', file, settingsWebpack5);
expect(resolved).to.have.property('found', true);
expect(resolved).to.have.property('path', null);
});

it('works on a function (synchronous) which uses getResolve for webpack 5', function () {
const resolved = webpack.resolve('graphql', file, settingsWebpack5);
expect(resolved).to.have.property('found', true);
expect(resolved).to.have.property('path', null);
});

it('prevents using an asynchronous function for webpack 5', function () {
const resolved = webpack.resolve('underscore', file, settingsWebpack5Async);
expect(resolved).to.have.property('found', false);
});

it('prevents using a function which uses Promise returned by getResolve for webpack 5', function () {
const resolved = webpack.resolve('graphql', file, settingsWebpack5Async);
expect(resolved).to.have.property('found', false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = {
externals: [
{ 'jquery': 'jQuery' },
'bootstrap',
async function ({ request },) {
if (request === 'underscore') {
return 'underscore'
}
},
function ({ request, getResolve }, callback) {
if (request === 'graphql') {
const resolve = getResolve()
// dummy call (some-module should be resolved on __dirname)
resolve(__dirname, 'some-module').then(
function () { callback(null, 'graphql') },
function (e) { callback(e) }
)
}
},
],
}
27 changes: 27 additions & 0 deletions resolvers/webpack/test/files/webpack.config.webpack5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = {
externals: [
{ 'jquery': 'jQuery' },
'bootstrap',
function ({ request }, callback) {
if (request === 'underscore') {
return callback(null, 'underscore')
}
callback()
},
function ({ request, getResolve }, callback) {
if (request === 'graphql') {
const resolve = getResolve()
// dummy call (some-module should be resolved on __dirname)
resolve(__dirname, 'some-module', function (err, value) {
if (err) {
callback(err)
} else {
callback(null, 'graphql')
}
})
} else {
callback()
}
},
],
}