Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to reorder plugin execution #6251

Open
hl037 opened this issue Jan 31, 2021 · 3 comments
Open

Add the ability to reorder plugin execution #6251

hl037 opened this issue Jan 31, 2021 · 3 comments

Comments

@hl037
Copy link

hl037 commented Jan 31, 2021

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
          });
        });
      }
    });
  }
}
@fangbinwei
Copy link
Collaborator

I prefer something like below

module.exports = (api, options) => {
//...
}
module.exports.before = ['@vue/cli-plugin-typescript']

@hl037
Copy link
Author

hl037 commented Jan 31, 2021

I like it, it would indeed be better

@leookun
Copy link

leookun commented Feb 4, 2024

topologicalSorting implementation of backward sorting, can't put my plugin on first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants