Skip to content

Commit

Permalink
special/webpack improvements (#449)
Browse files Browse the repository at this point in the history
* special/webpack: Manage TypeScript webpack definition

Issue #246

* special/webpack: Scan webpack entries for dependencies

Issue #446

* special/webpack: Detect babel-loader presets

Issue #448
  • Loading branch information
sveyret authored and rumpl committed Nov 1, 2019
1 parent 335a847 commit 40fa69c
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
55 changes: 50 additions & 5 deletions src/special/webpack.js
@@ -1,7 +1,7 @@
import path from 'path';
import lodash from 'lodash';

const webpackConfigRegex = /webpack(\..+)?\.conf(?:ig|)\.(babel\.)?js/;
const webpackConfigRegex = /webpack(\..+)?\.conf(?:ig|)\.(babel\.)?[jt]s/;
const loaderTemplates = ['*-webpack-loader', '*-web-loader', '*-loader', '*'];

function extractLoaders(item) {
Expand Down Expand Up @@ -44,6 +44,24 @@ function getLoaders(deps, loaders) {
.value();
}

function getBabelPresets(deps, loaders) {
return lodash(loaders || [])
.filter((item) =>
typeof item !== 'string'
&& item.loader
&& item.loader === 'babel-loader'
&& item.options
&& item.options.presets
&& Array.isArray(item.options.presets))
.map((item) => item.options.presets)
.flatten()
.map((preset) => (Array.isArray(preset) && preset.length > 0 ? preset[0] : preset))
.filter((preset) => typeof preset === 'string')
.intersection(deps)
.uniq()
.value();
}

function parseWebpack1(module, deps) {
const loaders = getLoaders(deps, module.loaders);
const preLoaders = getLoaders(deps, module.preLoaders);
Expand All @@ -66,18 +84,45 @@ function parseWebpack2(module, deps) {

const mappedLoaders = module.rules.filter((rule) => rule.loaders);
const mappedUses = mapRuleUse(module);
const loaders = getLoaders(deps, lodash.flatten([...mappedLoaders, ...mappedUses]));
return loaders;
const mapped = lodash.flatten([...mappedLoaders, ...mappedUses]);
const loaders = getLoaders(deps, mapped);
const presets = getBabelPresets(deps, mapped);
return [...loaders, ...presets];
}

function extractEntries(entries) {
if (typeof entries === 'string') {
return [entries];
}

if (Array.isArray(entries)) {
return entries.filter((entry) => typeof entry === 'string');
}

return Object.values(entries)
.filter((entry) => entry)
.map(extractEntries);
}

function parseEntries(entries, deps) {
return lodash(extractEntries(entries))
.flatten()
.intersection(deps)
.uniq()
.value();
}

export default function parseWebpack(content, filepath, deps) {
const filename = path.basename(filepath);
if (webpackConfigRegex.test(filename)) {
const module = require(filepath).module || {}; // eslint-disable-line global-require
const wpConfig = require(filepath); // eslint-disable-line global-require
const module = wpConfig.module || {};
const entry = wpConfig.entry || [];

const webpack1Loaders = parseWebpack1(module, deps);
const webpack2Loaders = parseWebpack2(module, deps);
return [...webpack1Loaders, ...webpack2Loaders];
const webpackEntries = parseEntries(entry, deps);
return [...webpack1Loaders, ...webpack2Loaders, ...webpackEntries];
}

return [];
Expand Down
47 changes: 46 additions & 1 deletion test/special/webpack.js
Expand Up @@ -13,6 +13,8 @@ const configFileNames = [
'webpack.prod.config.babel.js',
'webpack.prod.conf.js',
'webpack.base.conf.babel.js',
'webpack.config.ts',
'webpack.base.conf.babel.ts',
];

const testCases = [
Expand Down Expand Up @@ -182,6 +184,49 @@ const testCases = [
],
},
},
{
name: 'recognize dependency in simple entry',
deps: ['polyfill'],
entry: 'polyfill',
},
{
name: 'recognize dependency in array-type entry',
deps: ['polyfill', 'font'],
entry: ['polyfill', 'font', './src/app'],
},
{
name: 'recognize dependency in object-type simple entry',
deps: ['polyfill'],
entry: {
polyfill: 'polyfill',
app: './src/app'
},
},
{
name: 'recognize dependency in object-type array entry',
deps: ['polyfill', 'font'],
entry: {
polyfill: ['polyfill', 'font'],
app: './src/app'
},
},
{
name: 'recognize dependency in babel loader presets',
deps: ['babel-loader', '@babel/preset1', '@babel/preset2'],
module: {
rules: [
{
test: /\.js$/, use: {
loader: 'babel-loader',
options: { presets: [
['@babel/preset1', { option: 'option' }],
'@babel/preset2'
]},
}
},
],
},
},
{
name: 'handle invalid webpack config',
deps: [],
Expand Down Expand Up @@ -236,7 +281,7 @@ describe('webpack special parser', () => {
configFileNames.forEach(fileName =>
testCases.forEach(testCase =>
it(`should ${testCase.name} in configuration file ${fileName}`, () => {
const config = JSON.stringify({ module: testCase.module });
const config = JSON.stringify({ entry: testCase.entry, module: testCase.module });
const content = `module.exports = ${config}`;
return testWebpack(fileName, content, testCase.deps, testCase.deps);
})));
Expand Down

0 comments on commit 40fa69c

Please sign in to comment.