vue-cli
vue-cli copied to clipboard
Add the ability to reorder plugin execution
What problem does this feature solve?
Currently, plugins are executed in the order of the package.json dependency list. Since these dependencies are automatically alphabetically sorted by yarn install
, One plugin can suddenly break when renamed if it expect some other plugin to be executed before ( see https://stackoverflow.com/questions/65977135/how-to-change-chainwebpack-call-order-with-vue-js )
...This would also bring some determism to when each plugin is called
What does the proposed API look like?
An API could for example bring some kind of dependency graph across the plugins, like this :
First, the main export would be either a callback as it is currently, either an object. if it is an object, it would look like this :
{
before? : array<string>,
after? : array<string>,
name? : string,
callback : (api, options) => void),
metaPlugin? : boolean
}
metaPlugin
defaults to False. Indicates if callback
will contains only calls to api.addPlugin() (defined below). If it is set, before
, after
and name
should be left undefined/null/empty.
callback
is equivalent to the current exported function.
If metaPlugin
is not set :
name
, if set is the name of group this plugin is part of. if not set, it defaults to the package name.
before
and after
are the requirement lists of the plugin in the dependency graph. (other plugin's name)
Then an addPlugin()
api.addPlugin({
before? : array<string>,
after? : array<string>,
name? : string,
callback : (api, options) => void),
metaPlugin? : boolean
})
The fields have the same semantic as the exported object.
The plugin would be executed like this :
First, gather all (meta)plugin. Execute all meta-plugins "recursively" (a meta plugin can add another meta-plugin in its callback).
Then, solve the dep-graph and execute the remaining plugins. If not possible (cyclic dependencies), raise an error.
Example :
const dts = require('dts-bundle');
const path = require('path');
module.exports = {
metaPlugin : true
callback = (api, options) => {
api.addPlugin({
after : ["ts-loader"],
name : "ts-bundler",
callback : (api, options) => {
api.chainWebpack(config => {
//Disable thread-loader, cache-loader
const tsRule = config.module.rule('ts').test(/\.ts$/);
const tsxRule = config.module.rule('tsx').test(/\.tsx$/);
debugger
tsRule.uses.delete('cache-loader');
tsxRule.uses.delete('cache-loader');
tsRule.uses.delete('thread-loader');
tsxRule.uses.delete('thread-loader');
//Enable the generating of declaration files
tsRule
.use('ts-loader')
.loader('ts-loader')
.tap(opts => {
debugger
opts.compilerOptions = { declaration: true };
opts.transpileOnly = false;
opts.happyPackMode = false;
return opts;
});
});
//Bundle command
api.registerCommand('bundle-dts', {
description: 'Bundle the generated declaration files to a single file',
usage: 'vue-cli-service bundle-dts [options]',
}, async (args) => {
const config = api.resolveWebpackConfig();
const baseDir = config.output.path;
const entry = path.parse(config.entry.app[0]);
const main = path.resolve(baseDir, entry.dir, entry.name '.d.ts');
const name = require(api.resolve('package.json')).name;
delete args['_'];
if (args.main) {
const main = path.parse(args.main);
args.main = path.resolve(baseDir, main.dir, main.name '.d.ts');
}
dts.bundle({
...{ baseDir, main, name },
...args
});
});
}
});
}
}
I prefer something like below
module.exports = (api, options) => {
//...
}
module.exports.before = ['@vue/cli-plugin-typescript']
I like it, it would indeed be better
topologicalSorting implementation of backward sorting, can't put my plugin on first