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

feat: v6 - Environment API #16471

Draft
wants to merge 57 commits into
base: main
Choose a base branch
from
Draft

feat: v6 - Environment API #16471

wants to merge 57 commits into from

Conversation

patak-dev
Copy link
Member

@patak-dev patak-dev commented Apr 19, 2024

Description

Note

Check out the Environment API Docs

We're starting a new PR for the Environment API work in progress proposal for v6 to have a clean slate for reviews and discussions now that the implementation and docs are more stable.

This PR merges the work done in:

Refer to the discussions in these PRs for context. If you have general feedback about the APIs, let's use this discussion so we can have proper threads:

If you have comments about the implementation or would like to collaborate a feature, fix, test, or docs, please comment in this PR as an usual review or send a PR against the v6/environment-api branch.

Copy link

stackblitz bot commented Apr 19, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

patak-dev and others added 2 commits April 19, 2024 14:42
Co-authored-by: Vladimir Sheremet <[email protected]>
Co-authored-by: Hiroshi Ogawa <[email protected]>
Co-authored-by: 翠 / green <[email protected]>
Co-authored-by: Jun Shindo <[email protected]>
Co-authored-by: Greg T. Wallace <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Caven <[email protected]>
Co-authored-by: sapphi-red <[email protected]>
Co-authored-by: Matyáš Racek <[email protected]>
Co-authored-by: bluwy <[email protected]>
Co-authored-by: Igor Minar <[email protected]>
Co-authored-by: Vladimir <[email protected]>
Co-authored-by: 翠 / green <[email protected]>
Co-authored-by: Clément <[email protected]>
This was referenced Apr 19, 2024
@patak-dev patak-dev added this to the 6.0 milestone Apr 19, 2024
@patak-dev patak-dev added the p3-significant High priority enhancement (priority) label Apr 19, 2024
@patak-dev

This comment was marked as outdated.

@vite-ecosystem-ci

This comment was marked as outdated.

@hi-ogawa
Copy link
Collaborator

After 2866d4f, we have opt-in for build plugins to be shared, matching the way things work during dev. Individual plugins can set a sharedDuringBuild: true to opt-in, ...

I experimented with sharedDuringBuild for unocss on multi environment use cases (namely react server component) hi-ogawa/vite-environment-examples#57. It's still a minimal proof-of-concept (I picked up some code from original unocss plugin and tailwind v4 plugin), but my impression is that create(environment) and sharedDuringBuild: true nicely solved the concerns I had with using unocss for RSC. Awesome work!

It feels really nice to use, so only positive feedback here to confirm if I'm using it right:

  • since create(environment) provides environment.mode: "dev" | "build", I use it to split plugins for dev/build as well.
  • since environment already has environment.config, hot, moduleGraph etc..., I didn't need to access specific environment via server.environments.(env) via configureServer(server)

@patak-dev
Copy link
Member Author

It feels really nice to use, so only positive feedback here to confirm if I'm using it right:

  • since create(environment) provides environment.mode: "dev" | "build", I use it to split plugins for dev/build as well.

Yes, I think it makes sense to do it there. apply let's you do the same for a shared plugin so I think it still makes sense to also keep it.

  • since environment already has environment.config, hot, moduleGraph etc..., I didn't need to access specific environment via server.environments.(env) via configureServer(server)

You shouldn't be doing it either for shared plugins. You'll directly use this.environment in the hooks. We removed all configureServer(server) to access these in Vite's core. Or maybe you have other needs? Could you expand into why this.environment wasn't enough?

@hi-ogawa
Copy link
Collaborator

  • since environment already has environment.config, hot, moduleGraph etc..., I didn't need to access specific environment via server.environments.(env) via configureServer(server)

You shouldn't be doing it either for shared plugins. You'll directly use this.environment in the hooks. We removed all configureServer(server) to access these in Vite's core. Or maybe you have other needs? Could you expand into why this.environment wasn't enough?

Indeed, calling this.environment.hot during transform where the tokens are extracted can work normally, but it was a reminiscent of the original unocss plugin as it provides asynchronous onInvalidate listener, so I was setting up environment.hot callback there, something like:

export function vitePluginSharedUnocss(): Plugin {
  const ctx = getUnocssContext();

  return {
    ...
    create(environment) {
      if (environment.mode === "dev") {
        ctx.onInvalidate(() => environment.hot.send( .... ));
      }
      ...
    }
  }
}

@patak-dev
Copy link
Member Author

Indeed, calling this.environment.hot during transform where the tokens are extracted can work normally, but it was a reminiscent of the original unocss plugin as it provides asynchronous onInvalidate listener, so I was setting up environment.hot callback there (...)

Ah, this makes sense. Then yes, the new create hook is a good place to setup this listener. We should check if the listener is really needed now though. Interesting use case, thanks!

@patak-dev
Copy link
Member Author

We discussed with @sapphi-red and he proposed we move away from the create hook for bounded plugins, and use a factory (both Anthony and me preferred this form too initially). I actually started using a factory but switched to the create hook for the following reasons that I now think are not real blockers:

  • I felt that a function may not be enough in the future, imagine if we want to add more things like enforce or apply that needs to happen before the plugin gets evaluated. I think this may be a no-problem though, as we can first evaluate and then check the flags.
  • I thought that it wasn't easy to support enforce and that it would be needed. For example:
    function frameworkPlugin() {
      return [
        sharedPlugin(), // can have enforce: 'pre'
        () => isolatedPlugin() // it will stay separated from the prev plugin
      ]
    }
    This wasn't that bad at the end, enforce works in bounded plugins now
  • apply is evaluated before environments are created, so we need to make the last environment param optional or have a new hook. I think it isn't needed though, because we can pass environment as the argument when constructing the isolated plugin and that can be used for filtering
  • I thought that it will be easier to have backward compat with the create hook. Imagine if someone is reading plugins and now PluginOption also can be a function. We could have code broken at runtime or at types level. Maybe it is a price we should pay though.
  • I was also afraid that frameworks could not sniff the plugins to remove these isolated factories at config time anymore. But now that I think about it, we can use the same trick we have for middlewares and properly name the constructor functions so they could still remove them if they want. Or we only use shared plugins internally.

After [email protected], instead of

function plugin() {
  return {
    name: 'shared-plugin',
    create(environment) {
      return {
        name: 'bounded-plugin',
        transform() { ... }
      }
    }
  }
}

we switched to

function plugin() {
  return (environment) => {
    return {
      name: 'bounded-plugin',
      transform() { ... }
    }
  }
}

@hi-ogawa for the case you were having both a shared plugin hook and create in the same plugin, you can get the same by returning an array:

  [
    { name: 'shared-plugin', ... },
    (environment) => ({ name: 'bounded-plugin', ... }),
  ]

@patak-dev
Copy link
Member Author

/ecosystem-ci run

Comment on lines +169 to +172
/**
* Optimize deps config
*/
optimizeDeps?: DepOptimizationConfig
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like currently optimizeDeps.entries is not exposed (entries is in DepOptimizationOptions instead of DepOptimizationConfig). Is this intended?

  environments: {
    client: {
      dev: {
        optimizeDeps: {
          // this is currently type error
          entries: []
        },
      },

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand on a good use case for having different entries? These are only used while scanning, that is currently only enabled for the client environment. This is now an artificial limitation though. Given that we can properly issue a reload for all environments, we could opt-in into the full scanning + registering missing dependencies instead of a static list if we want.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, what I meant is only for client environment, just something equivalent of current root optimizeDeps.entries to help discovering deps early using initial esbuild scan.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current config.optimizeDeps.entries will be used during scan. But I think we should move it to environment options 👍🏼

@vite-ecosystem-ci
Copy link

📝 Ran ecosystem CI on cf9a79c: Open

suite result latest scheduled
analogjs failure success
astro failure success
histoire failure success
marko failure success
nuxt failure success
previewjs failure success
quasar failure success
qwik failure success
remix failure success
sveltekit failure success
unocss failure success
vike failure success
vite-plugin-react-swc failure success
vite-plugin-svelte failure success
vite-plugin-vue failure success
vite-setup-catalogue failure success
vitepress failure success
vitest failure failure

ladle, laravel, rakkas, vite-plugin-pwa, vite-plugin-react, vite-plugin-react-pages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3-significant High priority enhancement (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants