Giter VIP home page Giter VIP logo

vite-plugin-glob's Introduction

DEPRECATED: This plugin has be ported to back to Vite v3.0.


vite-plugin-glob

NPM version

The design experiment for import.meta.glob from Vite.

Motivations

There are quite some scenarios that import.meta.glob wasn't considered when it's been implemented at the beginning. So we received quite a few PRs to improve it.

However, some design considerations might conflict with each other. For example, #2495 support ignore option for glob import supports the ignore glob as a second argument, while in #6953 import.meta.glob support ?raw we uses the second argument to specify glob query (and later been changed to { as } via #7215 deprecate { assert: { type: raw }} in favor of { as: raw }).

There are several other PRs that touches it's design as well:

With these two TC39 proposals (import-reflection and import-assertions) not settled yet, combining with different needs and design tradeoffs in each PR, making the good API design for import.meta.glob directly in Vite core becoming harder and more and more complex than it could be (with the cautions to not break existing usages).

On top of that, in Vite we are having multiple macros for different options:

  • import.meta.glob
  • import.meta.globEager
  • import.meta.globEagerDefault (undocumented)

That results in a quite large API surface to maintain and make the future extension harder. For example, if we want import.meta.globNamed we might also need to add import.meta.globEagerNamed, making the counts to 5.

Thus I propose to experiment with the import.meta.glob as an external plugin so we could introduce breaking change more easier and ships the implementation much faster (in Vite it takes days for a change to be meraged, and weeks to months for it to be landed in stable release). And when we feel the new design is able to cover most of the use cases, then we could embed it into Vite core as a one-time breaking change in v3.0.

Features

  • Globing for multiple patterns
  • Globing ignore
  • HMR on file modification / addition / deletion
  • Ability to provide custom queries
  • Ability to only import default / named export
  • An unified API for different options
  • Vite alias
  • (Optional) Takeover Vite's import.meta.glob
  • Experiments

Install

npm i -D vite-plugin-glob
// vite.config.ts
import { defineConfig } from 'vite'
import GlobPlugin from 'vite-plugin-glob'

export default defineConfig({
  plugins: [
    GlobPlugin({
      // enable to let this plugin interpret `import.meta.glob`
      // takeover: true,
    }),
  ],
})

Usage

The API is named as import.meta.importGlob to avoid conflict with Vite's import.meta.glob in this implementation.

const modules = import.meta.importGlob('./dir/*.js')

/* {
  './dir/foo.js': () => import('./dir/foo.js'),
  './dir/bar.js': () => import('./dir/bar.js'),
} */

Multiple Globs

const modules = import.meta.importGlob([
  './dir/*.js',
  './another/dir/*.js',
])

/* {
  './dir/foo.js': () => import('./dir/foo.js'),
  './dir/bar.js': () => import('./dir/bar.js'),
  './another/dir/index.js': () => import('./another/dir/index.js'),
} */

Ignore Glob

Globs start with ! will be matched to exclude.

const modules = import.meta.importGlob([
  './dir/*.js',
  '!**/index.js',
])

Eager

Import the modules as static imports.

const modules = import.meta.importGlob('./dir/*.js', { eager: true })

/*
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}
*/

Import As

const modules = import.meta.importGlob('./dir/*.js', { as: 'raw' })

/* {
  './dir/foo.js': () => import('./dir/foo.js?raw'),
  './dir/bar.js': () => import('./dir/bar.js?raw'),
} */

Named Imports

It's possible to only import parts of the modules with the import options.

const setups = import.meta.importGlob('./dir/*.js', { import: 'setup' })

/* {
  './dir/foo.js': () => import('./dir/foo.js').then(m => m.setup),
  './dir/bar.js': () => import('./dir/bar.js').then(m => m.setup),
} */

Combining with eager, it's even possible to have tree-shaking enable for those modules.

const setups = import.meta.importGlob('./dir/*.js', { import: 'setup', eager: true })

/*
import { setup as __glob__0_0 } from './dir/foo.js'
import { setup as __glob__0_1 } from './dir/bar.js'
const setups = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}
*/

Set export to default to import the default export.

const modules = import.meta.importGlob('./dir/*.js', { import: 'default', eager: true })

/*
import __glob__0_0 from './dir/foo.js'
import __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}
*/

Custom Queries

const setups = import.meta.importGlob('./dir/*.js', { query: { foo: 'bar', bar: true } })

/* {
  './dir/foo.js': () => import('./dir/foo.js?foo=bar&bar=true&lang.js').then(m => m.setup),
  './dir/bar.js': () => import('./dir/bar.js?foo=bar&bar=true&lang.js').then(m => m.setup),
} */

Experiments

The following features are in experiments, feedbacks are greatly welcome!

Restore file extension when query is specified

Append fake &lang.(ext) when queries are specified, to preseve the file extension for following plugins to process.

Learn more at Discussions

This is disabled by default since v0.3.0. To enable it, pass restoreQueryExtension: true to plugin options.

TypeScript

Add to tsconfig.json

{
  "compilerOptions": {
    "types": [
      "vite-plugin-glob/client",
      // with takeover enabled
      // "vite-plugin-glob/takeover"
    ]
  }
}

You can use generic to specify the type of the modules.

interface SomeModule {
  name: string
  default: { /* ... */ }
}

import.meta.importGlob<SomeModule>('./dir/*.js')

Sponsors

License

MIT License © 2021 Anthony Fu

vite-plugin-glob's People

Contributors

antfu avatar brillout avatar cloydlau avatar nhedger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

vite-plugin-glob's Issues

Make paths relative from `config.root`

If we merge #5 then I would propose this:

// Pre-transform
import.meta.importGlob('/**/*.page.js')

// Post-transform today
{
  "../../../../../examples/vue/renderer/_default.page.client.js": () =>
    import("../../../../../examples/vue/renderer/_default.page.client.js")
}

// Post-transform proposal (`config.root` being `'/examples/vue/'`)
{
  "/renderer/_default.page.client.jsx": () =>
    import("../../../../../examples/vue/renderer/_default.page.client.jsx")
}

This is what Vite does today.

Unable to build on Cloudflare pages.

Hi!, I am able to build and host my project with the plugin properly on my local machine, but somehow I get this on the CI provided by CF Pages.

$ vite build
--
18:56:47.330 | failed to load config from /opt/buildhome/repo/vite.config.ts
18:56:47.330 | error during build:
18:56:47.330 | /opt/buildhome/repo/node_modules/vite-plugin-glob/dist/index.cjs:26
18:56:47.330 | server?.watcher.add(allGlobs.flatMap((i) => i.filter((i2) => i2[0] !== "!")));
18:56:47.331 |           ^
18:56:47.331 |  
18:56:47.331 | SyntaxError: Unexpected token '.'
18:56:47.331 | at wrapSafe (internal/modules/cjs/loader.js:1054:16)
18:56:47.331 | at Module._compile (internal/modules/cjs/loader.js:1102:27)
18:56:47.331 | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
18:56:47.331 | at Module.load (internal/modules/cjs/loader.js:986:32)
18:56:47.331 | at Function.Module._load (internal/modules/cjs/loader.js:879:14)
18:56:47.331 | at Module.require (internal/modules/cjs/loader.js:1026:19)
18:56:47.332 | at require (internal/modules/cjs/helpers.js:72:18)
18:56:47.332 | at Object.<anonymous> (/opt/buildhome/repo/vite.config.ts:33:39)
18:56:47.332 | at Module._compile (internal/modules/cjs/loader.js:1138:30)
18:56:47.332 | at Object.require.extensions.<computed> [as .ts] (/opt/buildhome/repo/node_modules/vite/dist/node/chunks/dep-8f5c9290.js:61963:20)
18:56:47.354 | error Command failed with exit code 1.
18:56:47.354 | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
18:56:47.371 | Failed: build command exited with code: 1

Thanks!

Windows support

Is there a plan for this? Maybe it's enough if we convert config.root and the fast-glob results to posix.

Error: Invalid glob import syntax: Expect CallExpression, got SequenceExpression

I try to get the plugin working with a fresh clean install of vite-plugin-ssr preact-client-routing-example. Please can you give a helping hand how to get this work. As soon as I add GlobPlugin() to plugins, it's throwing the error. I have setup a repo for reproduction:

https://github.com/jrson83/vite-plugin-glob-preact-example

Error: Invalid glob import syntax: Expect CallExpression, got SequenceExpression
    at err (D:\______jrson.de\preact-client-routing\node_modules\vite-plugin-glob\dist\index.cjs:97:17)
    at D:\______jrson.de\preact-client-routing\node_modules\vite-plugin-glob\dist\index.cjs:115:13
    at Array.map (<anonymous>)
    at parseImportGlob (D:\______jrson.de\preact-client-routing\node_modules\vite-plugin-glob\dist\index.cjs:93:24)
    at transform (D:\______jrson.de\preact-client-routing\node_modules\vite-plugin-glob\dist\index.cjs:208:23)
    at TransformContext.transform (D:\______jrson.de\preact-client-routing\node_modules\vite-plugin-glob\dist\index.cjs:72:28)
    at Object.transform (D:\______jrson.de\preact-client-routing\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:38900:53)
    at async doTransform (D:\______jrson.de\preact-client-routing\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:55857:29

Multiple Globs conflict when using both root-relative and file-relative globs

For example:

const modules = import.meta.importGlob([
  './*.js',
  '/*.js',
])

This requires two different fast-glob runs because ./*.js has cwd: basename(id) while /*.js has cwd: config.root.

We can solve this by discriminating globs into two buckets (one bucket per cwd value). Then we make one fast-glob run per bucket.

But things can get complex if we want to add support for parent-globbing import.meta.importGlob('../../*.js').

I'm wondering if Multiple Globs are worth the added complexity? Are Multiple Globs only about increasing performance by avoiding multiple fast-glob runs? Or is there another use case I'm not seeing?

Proposal: we drop support for Multiple Globs. But maybe I'm missing something here.

Alternatively, a solution would be:

// cwd: config.root
import.meta.glob(['*.js', '*.ts'], { from: 'root' })
// cwd: basename(id)
import.meta.glob(['*.js', '*.ts'], { from: '.' })
// cwd: `${basename(id)}/../../..}`
import.meta.glob(['*.js', '*.ts'], { from: '../../..' })

package.json type module

When using type: module in my projects package.json, I get the following error:

 npm run dev

> vite-plugin-glob-test@0.0.0 dev
> vite

failed to load config from D:\______mono\jrson.de\vite-plugin-glob-test\vite.config.ts
error when starting dev server:
file:///D:/______mono/jrson.de/vite-plugin-glob-test/node_modules/vite-plugin-glob/dist/index.mjs:1
import { scan, isMatch } from 'micromatch';
               ^^^^^^^
SyntaxError: Named export 'isMatch' not found. The requested module 'micromatch' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'micromatch';
const { scan, isMatch } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:128:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:194:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
    at async loadConfigFromFile (D:\______mono\jrson.de\vite-plugin-glob-test\node_modules\vite\dist\node\chunks\dep-3397b401.js:61680:31)
    at async resolveConfig (D:\______mono\jrson.de\vite-plugin-glob-test\node_modules\vite\dist\node\chunks\dep-3397b401.js:61224:28)
    at async createServer (D:\______mono\jrson.de\vite-plugin-glob-test\node_modules\vite\dist\node\chunks\dep-3397b401.js:59636:20)
    at async CAC.<anonymous> (D:\______mono\jrson.de\vite-plugin-glob-test\node_modules\vite\dist\node\cli.js:688:24)

I created a minimal setup for reproduction with create vite & preact-ts.

https://github.com/jrson83/vite-plugin-glob-module-issue

Performance

Currently, vite-plugin-glob sets fast-glob's option cwd to config.root (the user's root directory).

More performant would be to set the cwd depending on the glob. E.g.

// `vite-plugin-glob` should set the `cwd` to `${config.root}/some/nested/dir/`
import.meta.glob('/some/nested/dir/**/*.js')

So that fast-glob only considers /some/nested/dir/.

This is an optimization that can be done regardless of vite-plugin-glob; ideally this would be a patch to fast-glob.

Supporting custom parameters

The current proposal mentions support for a custom query.

I'm wondering if we could make that a bit more idiomatic for URLs that have custom parameters, such as in:

For example, as in this type of use case:

const images = import.meta.importGlob('./dir/*.jpg', { query: { preset: 'full' } })

/* {
  './dir/foo.jpg': () => import('./dir/foo.jpg?preset=full'),
  './dir/bar.jpg': () => import('./dir/bar.jpg?preset=full'),
} */

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.