Skip to content

Add the ability to reorder plugin execution #6251

Open
@hl037

Description

@hl037

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
          });
        });
      }
    });
  }
}

Activity

fangbinwei

fangbinwei commented on Jan 31, 2021

@fangbinwei
Collaborator

I prefer something like below

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

hl037 commented on Jan 31, 2021

@hl037
Author

I like it, it would indeed be better

leookun

leookun commented on Feb 4, 2024

@leookun

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @hl037@fangbinwei@leookun

        Issue actions

          Add the ability to reorder plugin execution · Issue #6251 · vuejs/vue-cli