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

Overview

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

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

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 Exports

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

const setups = import.meta.importGlob('./dir/*.js', { export: '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', { export: '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', { export: 'deafult', 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),
} */

Experimental: lang.(ext) will be added automatically to preseve the file extension for following plugins to process. Discussions.

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

Comments
  • feat: file extension restoration

    feat: file extension restoration

    Edit by @antfu:

    This PR introduces an experimental behavior that will append lang.(ext) when query is specified to keep the following plugins pipeline to process as the same file type.


    I guess you feel like queryRestoreFileExtension is too long? :-)

    opened by brillout 8
  • Multiple Globs conflict when using both root-relative and file-relative globs

    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: '../../..' })
    
    opened by brillout 8
  • Error: Invalid glob import syntax: Expect CallExpression, got SequenceExpression

    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
    
    opened by jrson83 4
  • Make paths relative from `config.root`

    Make paths relative from `config.root`

    If we merge https://github.com/antfu/vite-plugin-glob/pull/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.

    opened by brillout 3
  • Supporting custom parameters

    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'),
    } */
    
    opened by ElMassimo 3
  • Unable to build on Cloudflare pages.

    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!

    opened by sokryptk 1
  • fix: parsing with tailing comma, close #21

    fix: parsing with tailing comma, close #21

    See comments in the PR code.

    I'm a little lost at how parseImportGlob() works so I'm thinking it's probably best if someone familiar with that AST parsing has a look at it.

    opened by brillout 1
  • package.json type module

    package.json type module

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

    ❯ npm run dev
    
    > [email protected] 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

    opened by jrson83 1
  • Performance

    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.

    opened by brillout 1
  • fix: HMR

    fix: HMR

    HMR didn't work; this fixes it.

    In principle, HMR should just work, since, from Vite's perspective, vite-plugin-glob returns just a bunch of imports. This means that HMR should just work. With one exception: we need to invalidate the importer if a matching file is created/removed. This is what this PR does.

    I tested this and it seems to work.

    opened by brillout 0
  • perf: automatically reduce search space

    perf: automatically reduce search space

    Not only does this considerably increase performance, but it also enables globbing into node_modules/ while preserving ignore: ['**/node_modules/**'].

    Both Hydrogen and vps frameworks need globs such as node_modules/framework/**/*.page.js.

    opened by brillout 0
Releases(v0.3.2)
Owner
Anthony Fu
A ship in harbor is safe, but that is not what ships are built for.
Anthony Fu
Vite-plugin-web-extension - A vite plugin for generating cross browser platform, ES module based web extensions.

vite-plugin-web-extension A vite plugin for generating cross browser platform, ES module based web extensions. Features Manifest V2 & V3 Support Compl

Ruben Medina 81 Dec 31, 2022
Vue 3 + Vite + SSR template based on Vite Plugin SSR and inspired by Vitesse

Vite Vue SSR Starter Vue 3 + Vite + SSR template based on Vite Plugin SSR and inspired by Vitesse Features ⚡️ Vue 3, Vite 2, TypeScript ?? Domain-Driv

Oleg Koval 10 Aug 2, 2022
Easy generation of OpenGraph & Twitter meta-tags in Nuxt 3 📋

nuxt-social-tags Easy generation of OpenGraph & Twitter meta-tags in Nuxt 3 ✨ Release Notes ?? Read the documentation Features Nuxt3 ready Composables

Conner 19 Dec 17, 2022
The fullstack Angular meta-framework

Analog Analog is a meta-framework for building applications and websites with Angular. Getting Started Use your package manager of choice to create a

null 583 Dec 23, 2022
Automatically detect and import components or modules

vite-plugin-autoimport Automatically detect and import components or modules. Motivation It's very common to have many components in one file as the p

Yuan Chuan 146 Dec 23, 2022
Vue2.x plugin to create scoped or global shortcuts. No need to import a vue component into the template.

vue2-shortcut Vue2.x plugin to create scoped or global shortcuts. No need to import a vue component into the template. Install $ npm install --save vu

Graxi 37 Aug 14, 2022
A Marko plugin for Vite

@marko/vite A Marko plugin for Vite. Installation npm install @marko/vite Example config import { defineConfig } from "vite"; import marko from "@mark

Marko 49 Nov 26, 2022
🎉 基于 vite 2.0 + vue 3.0 + vue-router 4.0 + vuex 4.0 + element-plus 的后台管理系统vue3-element-admin

vue3-element-admin ?? 基于 Vite 2.0 + Vue3.0 + Vue-Router 4.0 + Vuex 4.0 + element-plus 的后台管理系统 简介 vue3-element-admin 是一个后台前端解决方案,它基于 vue3 和 element-plu

雪月欧巴 84 Nov 28, 2022
Vite template with TypeScript, Chakra UI, Eslint Airbnb, Prettier

Vite + Typescript + ChakraUI = ❤️ This is a vite template that combines several technologies: Vite React TypeScript ChakraUI Eslint with eslint-config

Lorenzo Rapetti 3 Mar 26, 2022
Integrate Tauri in a Vite project to build cross-platform apps.

vite-plugin-tauri Integrate Tauri in a Vite project to build cross-platform apps Install Make sure to setup your environment for Tauri development. Th

Amr Bashir 95 Dec 15, 2022
A template repository / quick start to build Azure Static Web Apps with a Node.js function. It uses Vue.js v3, Vue Router, Vuex, and Vite.js.

Azure Static Web App Template with Node.js API This is a template repository for creating Azure Static Web Apps that comes pre-configured with: Vue.js

Marc Duiker 6 Jun 25, 2022
⏳ vue3 + electron + ts + vite = mini template

v3-electron ?? Electron16 + Vue3 + Vite2 运行项目 # enter the project directory cd v3-electron # install dependency yarn # develop yarn dev # build exe

UNPany 8 Nov 11, 2022
Using Cypress with Vite, React, TypeScript, MSW and react-query

Vie + Cypress + MSW + react-query Demo Example of using Cypress with Vite, MSW and react-query. Uses the appReady pattern to signal to Cypress when th

Rob Caldecott 9 Jul 16, 2022
Fastify boilerplate with Vite & Vitest

Fastify boilerplate with Vite & Vitest Enhance your Fastify DX with the power of Vite & Vitest. Features ⚡ All the power of Vite (Next Generation Fron

Emmanuel Salomon 31 Dec 13, 2022
Some compile-time magic for your Vite project

?? You can help the author become a full-time open-source maintainer by sponsoring him on GitHub. vite-plugin-compile-time Use this plugin to generate

EGOIST 90 Dec 15, 2022
vite+vue3.2+setup+elementPlus+eslint+js+stylelint

前期准备工作,npm包和vscode配置 !!!很重要,关乎整个Vue3开发阶段的代码提示 Volar使用 使用Vue3开发需要禁用vscode插件Vetur 然后安装 Volar(Vue Language Features),这样Vue3代码提示即使是使用js开发也非常友好 如果volar没有任何

null 2 Feb 8, 2022
vue3 + vite + typescript template

Vue 3 + Typescript + Vite This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 <script setu

BrowLi 6 Aug 1, 2022
Minimal setup for a WebXR project using Vite, Babylon.js, TypeScript, and Vue

WebXR-Vite-Babylon-Simple Minimal setup for WebXR development using: vite typescript vue 3 babylonjs 5 (ES6) Intentionally made minimal changes from t

Josh Sanderson 6 Nov 13, 2022
Modern ThreeJS boilerplate powered by Vite & Typescript

Modern ThreeJS ⚡️ Modern ThreeJS boilerplate powered by Vite & Typescript. Features Powered with Vite ?? GUI controls using Tweakpane ?? Typescript ??

Alvaro Saburido 64 Jan 4, 2023