Skip to content

Commit

Permalink
feat: support module.rules config
Browse files Browse the repository at this point in the history
  • Loading branch information
hubcarl committed Nov 20, 2018
1 parent a3649ba commit e37d181
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 28 deletions.
28 changes: 22 additions & 6 deletions lib/core/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,7 @@ class Config {
if (this._typescript) {
return this._typescript;
}
const typescript = this.getLoaderByName('ts');
if (this.utils.isObject(typescript) && this.utils.isTrue(typescript.enable)) {
this._typescript = typescript;
}
this._typescript = this.isUseLoader('ts');
return this._typescript;
}

Expand Down Expand Up @@ -340,12 +337,31 @@ class Config {
return this.utils.isTrue(enable);
}

isUseLoader(name) {
const configInfo = this.getMergeLoaderByName(name)[name];
return this.isUseConfig(configInfo);
}

isUsePlugin(name) {
const configInfo = this.getPluginByName(name);
return this.isUseConfig(configInfo);
}

isUseConfig(configInfo) {
return configInfo && this.isType(configInfo.type) && this.isEnv(configInfo.env) && this.isEnable(configInfo.enable);
}

isUse(name, range = 'plugin') {
if (this.utils.isBoolean(name)) {
return name;
}
const configInfo = this.utils.isObject(name) ? name : (range === 'plugin' ? this.getPluginByName(name) : this.getLoaderByName(name));
return configInfo && this.isType(configInfo.type) && this.isEnv(configInfo.env) && this.isEnable(configInfo.enable);
if (this.utils.isObject(name)) {
return this.isUseConfig(name);
}
if (range === 'plugin') {
return this.isUsePlugin(name);
}
return this.isUseLoader(name);
}

isWebpackLoader(loader) {
Expand Down
47 changes: 34 additions & 13 deletions lib/core/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const { STYLE_LOADER } = require('../core/constant');

module.exports = {

getLoaderLabel(loader) {
return this.utils.getLoaderLabel(loader, this);
},

getConfigLoader(config) {
const { loaders = {} } = config;
const { rules = [] } = config.module || {};
Expand All @@ -26,18 +30,29 @@ module.exports = {
}

return rules.find(loader => {
const label = this.utils.getLoaderLabel(loader);
const label = this.getLoaderLabel(loader);
if (name === label || mappingName === label) {
return true;
}
return false;
});
},

getLoaderByName(name) {
getMergeLoaderByName(name) {
const defaultLoader = this.utils.cloneDeep(this.loaders[name]);
const configLoader = this.getConfigLoaderByName(name);
return this.mergeLoader({ [name]: configLoader }, { [name]: defaultLoader })[name];
return this.mergeLoader({ [name]: configLoader }, { [name]: defaultLoader });
},

getLoaderByName(name) {
const loader = this.getMergeLoaderByName(name);
const options = this.merge(this.config.loaderOptions, this.loaders.options);
const loaders = this.mergeLoaderOption(loader, options);
const webpackLoaders = this.createLoader(loaders);
if (webpackLoaders.length) {
return webpackLoaders[0];
}
return {};
},

initLoader() {
Expand Down Expand Up @@ -143,6 +158,17 @@ module.exports = {
return null;
},

getTsLoader() {
const itemLoader = this.getLoaderByName('ts');
if (itemLoader && itemLoader.use) {
const tsLoader = itemLoader.use.find(loader => {
return this.utils.isObject(loader) && loader.loader === 'ts-loader';
});
return tsLoader;
}
return null;
},

addLoader(loader) {
if (loader.test && (loader.use || loader.loader)) {
const loaderInfo = {};
Expand All @@ -167,7 +193,7 @@ module.exports = {
const sourceLoaders = Array.isArray(cloneLoaders) ? {} : cloneLoaders;
if (Array.isArray(cloneLoaders)) {
cloneLoaders.forEach(loader => {
const label = this.utils.getLoaderLabel(loader);
const label = this.getLoaderLabel(loader);
if (this.isWebpackLoader(loader)) {
sourceLoaders[label] = this.merge(loader, { enable: true });
} else {
Expand Down Expand Up @@ -213,7 +239,7 @@ module.exports = {
}
if (Array.isArray(itemLoader.use)) {
itemLoader.use.forEach((loader, index) => {
const label = this.utils.getLoaderLabel(loader);
const label = this.getLoaderLabel(loader);
const mLabel = this.loaderKeyLabelMapping[name];
const configOptions = itemLoader.options && (label === mLabel || label === name) ? itemLoader.options : {};
const options = this.merge(loaderOptions[label], { options: configOptions });
Expand Down Expand Up @@ -275,7 +301,7 @@ module.exports = {
});
loaderNames.forEach(name => {
const itemLoader = loaders[name];
['type', 'enable', 'postcss', 'framework', 'loader', 'options'].forEach(propery => {
['type', 'enable', 'postcss', 'framework', 'loader', 'options', 'name'].forEach(propery => {
delete itemLoader[propery];
});
});
Expand Down Expand Up @@ -320,13 +346,8 @@ module.exports = {
// https://github.com/TypeStrong/ts-loader/pull/782
// vue-loader 14 版本中,需在 options 重复配置 ts-loader,升级 15 以后可移除
if (this.typescript) {
const use = this.utils.isFunction(this.typescript.use) ? this.typescript.use.apply(this) : this.typescript.use;
const tsLoader = use.find(item => {
return item.loader === 'ts-loader';
});
if (tsLoader) {
loaders.ts = tsLoader;
}
const tsLoader = this.getTsLoader();
loaders.ts = tsLoader;
}
return { preLoaders, loaders };
},
Expand Down
131 changes: 131 additions & 0 deletions test/vue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,136 @@ describe('vue.test.js', () => {
const webpackConfig = builder.create();
expect(webpackConfig.output.path).to.equal(path.join(__dirname, '../app/view'));
});

it('should vue ts framework loaders test', () => {
const builder = new WebpackServerBuilder({
loaders: {
ts: true,
vue: {
test: /\.vue$/,
exclude: /node_modules/,
use() {
const options = this.createFrameworkLoader('vue-style-loader');
options.transformToRequire = { img: ['url', 'src'] };
return [
{
loader: 'vue-loader',
options
}
];
}
}
}
});
const webpackConfig = builder.create();
const vueLoader = helper.getLoaderByName('vue', webpackConfig.module.rules);
expect(vueLoader.use[0].options.loaders).to.include.keys(['ts', 'js', 'css']);
});
it('should vue typescript loaders framework test', () => {
const builder = new WebpackServerBuilder({
loaders: {
typescript: true,
vue: {
test: /\.vue$/,
exclude: /node_modules/,
use() {
const options = this.createFrameworkLoader('vue-style-loader');
options.transformToRequire = { img: ['url', 'src'] };
return [
{
loader: 'vue-loader',
options
}
];
}
}
}
});
const webpackConfig = builder.create();
const vueLoader = helper.getLoaderByName('vue', webpackConfig.module.rules);
expect(vueLoader.use[0].options.loaders).to.include.keys(['ts', 'js', 'css']);
});
it('should vue typescript module rules test', () => {
const builder = new WebpackServerBuilder({
module: {
rules: [
{ typescript: true },
{
vue: {
test: /\.vue$/,
exclude: /node_modules/,
use() {
const options = this.createFrameworkLoader('vue-style-loader');
options.transformToRequire = { img: ['url', 'src'] };
return [
{
loader: 'vue-loader',
options
}
];
}
}
}
]
}
});
const webpackConfig = builder.create();
const vueLoader = helper.getLoaderByName('vue', webpackConfig.module.rules);
expect(vueLoader.use[0].options.loaders).to.include.keys(['ts', 'js', 'css']);
});
it('should vue ts module rules test', () => {
const builder = new WebpackServerBuilder({
module: {
rules: [
{ ts: true },
{
vue: {
test: /\.vue$/,
exclude: /node_modules/,
use() {
const options = this.createFrameworkLoader('vue-style-loader');
options.transformToRequire = { img: ['url', 'src'] };
return [
{
loader: 'vue-loader',
options
}
];
}
}
}
]
}
});
const webpackConfig = builder.create();
const vueLoader = helper.getLoaderByName('vue', webpackConfig.module.rules);
expect(vueLoader.use[0].options.loaders).to.include.keys(['ts', 'js', 'css']);
});
it('should vue ts module rules native config test', () => {
const builder = new WebpackServerBuilder({
module: {
rules: [
{ ts: true },
{
test: /\.vue$/,
exclude: /node_modules/,
use() {
const options = this.createFrameworkLoader('vue-style-loader');
options.transformToRequire = { img: ['url', 'src'] };
return [
{
loader: 'vue-loader',
options
}
];
}
}
]
}
});
const webpackConfig = builder.create();
const vueLoader = helper.getLoaderByName('vue', webpackConfig.module.rules);
expect(vueLoader.use[0].options.loaders).to.include.keys(['ts', 'js', 'css']);
});
});
});
21 changes: 12 additions & 9 deletions utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,20 +271,23 @@ utils.getLoaderOptionString = (name, options) => {
return optionStr;
};

utils.getLoaderLabel = loader => {
utils.getLoaderLabel = (loader, ctx) => {
let loaderName = loader;
if (utils.isObject(loader)) {
if (loader.loader) {
if (loader.name) {
loaderName = loader.name;
} else if (loader.loader) {
loaderName = loader.loader;
} else if (Array.isArray(loader.use)) {
loaderName = loader.use.reduce((name, item) => {
} else if (Array.isArray(loader.use) || utils.isFunction(loader.use)) {
const loaders = utils.isFunction(loader.use) ? loader.use.apply(ctx) : loader.use;
loaderName = loaders.reduce((names, item) => {
if (utils.isString(item)) {
name += item;
} else {
name += item.loader;
names.push(item.replace(/-loader$/, ''));
} else if (item.loader) {
names.push(item.loader.replace(/-loader$/, ''));
}
return name;
}, '');
return names;
}, []).join('-');
} else if (Object.keys(loader).length === 1) {
loaderName = Object.keys(loader)[0];
}
Expand Down

0 comments on commit e37d181

Please sign in to comment.