Giter VIP home page Giter VIP logo

unimport's Introduction

unimport

npm version npm downloads Codecov

Unified utils for auto importing APIs in modules, used in nuxt and unplugin-auto-import

Features

  • Auto import register APIs for Vite, Webpack or esbuild powered by unplugin
  • TypeScript declaration file generation
  • Auto import for custom APIs defined under specific directories
  • Auto import for Vue template

Install

# npm
npm install unimport

# yarn
yarn add unimport

# pnpm
pnpm install unimport

Usage

Plugin Usage

Powered by unplugin, unimport provides a plugin interface for bundlers.

Vite / Rollup

// vite.config.js / rollup.config.js
import Unimport from 'unimport/unplugin'

export default {
  plugins: [
    Unimport.vite({ /* plugin options */ })
  ]
}

Webpack

// webpack.config.js
import Unimport from 'unimport/unplugin'

module.exports = {
  plugins: [
    Unimport.webpack({ /* plugin options */ })
  ]
}

Programmatic Usage

// ESM
import { createUnimport } from 'unimport'

// CommonJS
const { createUnimport } = require('unimport')
const { injectImports } = createUnimport({
  imports: [{ name: 'fooBar', from: 'test-id' }]
})

// { code: "import { fooBar } from 'test-id';console.log(fooBar())" }
console.log(injectImports('console.log(fooBar())'))

Configurations

Imports Item

Named import
imports: [
  { name: 'ref', from: 'vue' },
  { name: 'useState', as: 'useSignal', from: 'react' },
]

Will be injected as:

import { ref } from 'vue'
import { useState as useSignal } from 'react'
Default import
imports: [
  { name: 'default', as: '_', from: 'lodash' }
]

Will be injected as:

import _ from 'lodash'
Namespace import
imports: [
  { name: '*', as: '_', from: 'lodash' }
]

Will be injected as:

import * as _ from 'lodash'
Custom Presets

Presets are provided as a shorthand for declaring imports from the same package:

presets: [
  {
    from: 'vue',
    imports: [
      'ref',
      'reactive',
      // ...
    ]
  }
]

Will be equivalent as:

imports: [
  { name: 'ref', from: 'vue' },
  { name: 'reactive', from: 'vue' },
  // ...
]
Built-in Presets

unimport also provides some builtin presets for common libraries:

presets: [
  'vue',
  'pinia',
  'vue-i18n',
  // ...
]

You can check out src/presets for all the options available or refer to the type declaration.

Exports Auto Scan

Since unimport v0.7.0, we also support auto scanning the examples from a local installed package, for example:

presets: [
  {
    package: 'h3',
    ignore: ['isStream', /^[A-Z]/, /^[a-z]*$/, r => r.length > 8]
  }
]

This will be expanded into:

imports: [
  {
    from: 'h3',
    name: 'appendHeader',
  },
  {
    from: 'h3',
    name: 'appendHeaders',
  },
  {
    from: 'h3',
    name: 'appendResponseHeader',
  },
  // ...
]

The ignore option is used to filter out the exports, it can be a string, regex or a function that returns a boolean.

By default, the result is strongly cached by the version of the package. You can disable this by setting cache: false.

Type Declarations

Unimport.vite({
  dts: true // or a path to generated file
})

Directory Auto Import

dirs: [
  './composables/*'
]

Named exports for modules under ./composables/* will be registered for auto imports.

Opt-out Auto Import

You can opt-out auto-import for specific modules by adding a comment:

// @unimport-disable

It can be customized by setting commentsDisable:

Unimport.vite({
  commentsDisable: [
    '@unimport-disable',
    '@custom-imports-disable',
  ]
})

Acorn Parser

By default, unimport uses RegExp to detect unimport entries. In some cases, RegExp might not be able to detect all the entries (false positive & false negative).

We introduced a new AST-based parser powered by acorn, providing a more accurate result. The limitation is when using Acorn, it assumes all input code are valid and vanilla JavaScript code.

Unimport.vite({
  parser: 'acorn'
})

Vue Template Auto Import

In Vue's template, the usage of API is in a different context than plain modules. Thus some custom transformations are required. To enable it, set addons.vueTemplate to true:

Unimport.vite({
  addons: {
    vueTemplate: true
  }
})

Caveats

When auto-import a ref, inline operations won't be auto-unwrapped.

export const counter = ref(0)
<template>
  <!-- this is ok -->
  <div>{{ counter }}</div>

  <!-- counter here is a ref, this won't work, volar will throw -->
  <div>{{ counter + 1 }}</div>

  <!-- use this instead -->
  <div>{{ counter.value + 1 }}</div>
</template>

We recommend using Volar for type checking, which will help you to identify the misusage.

๐Ÿ’ป Development

  • Clone this repository
  • Enable Corepack using corepack enable (use npm i -g corepack for Node.js < 16.10)
  • Install dependencies using pnpm install
  • Run interactive tests using pnpm dev

License

Made with ๐Ÿ’›

Published under MIT License.

unimport's People

Contributors

a145789 avatar amaury-tobias avatar antfu avatar brawaru avatar cinob avatar danielroe avatar imba97 avatar ineshbose avatar jaw52 avatar kazariex avatar kiki-kanri avatar kingyue737 avatar lehni avatar leo-buneev avatar lishaobos avatar mannil avatar minenwerfer avatar pi0 avatar qmhc avatar renovate[bot] avatar rivermanbw avatar rubiin avatar sxzz avatar tangdaoyuan avatar tmg0 avatar weilence avatar wesdimiceli avatar woldtwerk avatar yassilah avatar yiin 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  avatar  avatar  avatar

unimport's Issues

Missing dependency `vue/compiler-sfc`?

I forked this repo in order to hunt down a bug with commented out exports (cc: nuxt/nuxt#14971) and I noticed after npm installing that there's a dependency on vue/compiler-sfc, failing a test. I think it just needs to be @vue/compiler-sfc.

Side note (and I can open another issue for this if required), when running npm run dev the absolute import test fails as it tries to find a.vue which doesn't exist in the project.

Generated import paths strips anything preceded by a dot (file.dto.ts ...)

Environment


  • Operating System: Darwin
  • Node Version: v18.16.0
  • Nuxt Version: 3.8.2
  • CLI Version: 3.10.0
  • Nitro Version: 2.8.1
  • Package Manager: [email protected]
  • Builder: -
  • User Config: -
  • Runtime Modules: -
  • Build Modules: -

Reproduction

Here's a stackblitz minimal reproduction :
https://stackblitz.com/edit/nuxt-starter-jxv1vc?file=.nuxt%2Ftypes%2Fimports.d.ts

Describe the bug

  1. A folder 'services' contains a file 'demo.service.ts
  2. services forlder is flagged for auto import on config

Produced entry on imports.d.ts :

  const someDemoFunction: typeof import('../../services/demo')['someDemoFunction']

The '.service' part of the file name have been stripped away

Additional context

No response

Logs

No response

Unimport doesn't work with shebang in entry file.

Environment

Stackblitz node cli project.
node: v18.18.0

Reproduction

https://stackblitz.com/edit/stackblitz-starters-hv4vuo

Describe the bug

I am not sure if this issue is caused by tsup or unimport.
In a Node CLI project, if the entry file includes a shebang code like #!/usr/bin/env node, then it must be explicitly declared for import, otherwise it will cause an error message like โœ˜ [ERROR] Syntax error "!

tsup.config.ts

import { defineConfig } from 'tsup';
import Unimport from 'unimport/unplugin';

export default defineConfig((options) => ({
  entry: ['./src'],
  format: ['esm'],
  esbuildPlugins: [Unimport.esbuild({ dts: true, dirs: ['./src'] })],
}));

entry file: src/cli.ts

#!/usr/bin/env node
output();

Additional context

No response

Logs

CLI Building entry: src/cli.ts, src/utils.ts
CLI Using tsconfig: tsconfig.json
CLI tsup v8.0.1
CLI Using tsup config: /home/projects/stackblitz-starters-hv4vuo/tsup.config.ts
CLI Target: esnext
ESM Build start
โœ˜ [ERROR] Syntax error "!"

    src/cli.ts:2:1:
      2 โ”‚ #!/usr/bin/env node
        โ•ต  ^

ESM Build failed
Error: Build failed with 1 error:
src/cli.ts:2:1: ERROR: Syntax error "!"
    at failureErrorWithLog (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1641:15)
    at eval (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1049:25)
    at runOnEndCallbacks (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1476:45)
    at buildResponseToResult (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1047:7)
    at eval (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1076:16)
    at responseCallbacks.<computed> (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:694:9)
    at handleIncomingPacket (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:754:9)
    at Socket.readFromStdout (/home/projects/stackblitz-starters-hv4vuo/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:670:7)
    at EventEmitter.emit (node:events:42:9202)
    at addChunk (node:internal/streams/readable:105:4109)
โ€‰ELIFECYCLEโ€‰ Command failed with exit code 1.

Duplicated imports vue and vueuse

Environment

node20

Reproduction

https://codesandbox.io/p/sandbox/focused-haslett-ttp84n?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clp6po45e00082v6bitniks05%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clp6po45d00032v6bz5o2ju4m%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clp6po45d00052v6bpfk8cfu1%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clp6po45d00072v6bzrez3vr0%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clp6po45d00032v6bz5o2ju4m%2522%253A%257B%2522id%2522%253A%2522clp6po45d00032v6bz5o2ju4m%2522%252C%2522activeTabId%2522%253A%2522clp6pqrnb00s42v6b1jr2xlem%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clp6po45d00022v6btgge2w19%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fvite.config.ts%2522%252C%2522id%2522%253A%2522clp6pot4f008c2v6b9x1z0cxt%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Fcomponents%252FHelloWorld.vue%2522%252C%2522id%2522%253A%2522clp6pqrnb00s42v6b1jr2xlem%2522%252C%2522mode%2522%253A%2522temporary%2522%257D%255D%257D%252C%2522clp6po45d00072v6bzrez3vr0%2522%253A%257B%2522id%2522%253A%2522clp6po45d00072v6bzrez3vr0%2522%252C%2522activeTabId%2522%253A%2522clp6pq0dt00od2v6biw7r573y%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clp6po45d00062v6bl0wsi81d%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522npm%2520run%2520dev%2522%252C%2522port%2522%253A5174%252C%2522path%2522%253A%2522%252F%2522%257D%252C%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522npm%2520run%2520dev%2522%252C%2522port%2522%253A5173%252C%2522id%2522%253A%2522clp6pq0dt00od2v6biw7r573y%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%257D%252C%2522clp6po45d00052v6bpfk8cfu1%2522%253A%257B%2522id%2522%253A%2522clp6po45d00052v6bpfk8cfu1%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clp6po45d00042v6bw51w8mjm%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522npm%2520run%2520dev%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clp6po45d00042v6bw51w8mjm%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A20.546875%257D

Describe the bug

When using vue and vueuse presets you get duplicated imports:

Duplicated imports "toRef", the one from "vue" has been ignored and "@vueuse/core" is used
Duplicated imports "toValue", the one from "vue" has been ignored and "@vueuse/core" is used

Should this be addressed in the preset? Can this be resolved via config?

Additional context

No response

Logs

Duplicated imports "toRef", the one from "vue" has been ignored and "@vueuse/core" is used
Duplicated imports "toValue", the one from "vue" has been ignored and "@vueuse/core" is used

mongoose and jasonwebtocket autoimport

Describe the feature

How do you guys do something like this? Why it works in case of zod but not in case of mongoose and jasonwebtocket?

{
imports: [
        {
          from: "jsonwebtoken",
          name: "default",
          as: "jwt",
        },
      ],
      presets: [
        {
          from: "zod",
          imports: ["z"],
        },
        {
          from: "mongoose",
          imports: ["model"],
        }
      ],
}
image image image

Additional information

  • Would you be willing to help implement this feature?

Auto extract package exports

We can directly use the npm package to automatically detect their exports and use it as a preset. Currently, it is only possible to use manual presets and a list of their exports.

In order to extract exports, we have 3 possible ways:

  • Actually require package in an isolated runtime and check the exports
  • Use static syntax analyses to detect exports
  • Use metadata directly exported from packages

Using the last method is safest because packages can exactly annotate their exports and use a built step plugin (unbuild or rollup) to automate this meta generation process into dist/unimport.json. We can then refer it from package.json using "unimport": "./dist/unimport.json"

When packages are not bundled in this way, we can fallback to mlly.resolveModuleExportNames and use fast static analyzes to extract export names.

In order to have better control over auto-infered exports, we might exprot a filter function from presets. I imagine preset looking like this:

presets: [{
  package: 'h3',
  exports: 'auto' | 'analyze' // Default is auto - Tries `autoImport` in pacakge.json then analyzes
  ignore: ['h', (name) => !name.startsWith('use')]
}]

In order to speed up the performance, we might use global cache in {os.tmpDir}/unimport/{package}/{version}/exports.json containing exports and an integrity field to validate cache entry.

(This is a summary of discussing together with @antfu)

esm import results in faulty cjs require

Environment

18.15.0

Reproduction

import Unimport from 'unimport/unplugin'

export default (options: UserOptions = {}): Plugin[] => {
return [
   ...
    UnimportPlugin.vite(),
    ...
  ].flat()
}

Describe the bug

gets compiled to:

const index = (options = {}) => {
const Unimport = require('unimport/unplugin');
const UnimportPlugin = "default" in Unimport ? Unimport.default : Unimport;
  return [
    ...
    Unimport.vite(),
    ...
  ].flat();
};

module.exports = index;

It should be Unimport.default.vite though

is this an issue with unimport or unbuild?

I'm using "unbuild": "^1.1.2"

Additional context

The use case is that I have a meta plugin that preconfigures a bunch of plugins.

I have a workaround, but would like to know why this happens.
Thank you =)

Logs

No response

Auto-import for enum is not working: TS2749: 'User' refers to a value, but is being used as a type

Environment

Environment: Stackblitz ๐Ÿ‘ˆ๏ธ

Working directory: /home/projects/github-68jxaq                                                                12:13:23 PM
Nuxt project info:                                                                                             12:13:23 PM

------------------------------
- Operating System: Linux
- Node Version:     v18.18.0
- Nuxt Version:     3.9.3
- CLI Version:      3.10.0
- Nitro Version:    2.8.1
- Package Manager:  [email protected]
- Builder:          -
- User Config:      devtools, imports
- Runtime Modules:  -
- Build Modules:    -
------------------------------

Reproduction

https://stackblitz.com/edit/github-68jxaq?file=package.json,app.vue

Describe the bug

I noticed in Nuxt that auto-import for TypeScript enums was not working, so I reported it to Nuxt #25311 but as @manniL mentioned in that issue, this is an upstream bug with unimport itself so I am opening the issue here. I am not familiar with unimport or how it works and I wasn't able to get an example up and running with it but I do have a Nuxt reproduction and I hope that helps.

Here is the issue - I have a TypeScript enum in common/types/user.ts and I want to use this enum in my app. (see Stackblitz reproduction). And it gets auto-imported by Nuxt but it seems to do it wrongly. Because if I manually import it myself it works (typechecker does not complain). But if I let Nuxt auto-import do it then then typechecker is throwing this error:

$ npm run typecheck
> vue-tsc --noEmit

app.vue:9:23 - error TS2749: 'User' refers to a value, but is being used as a type here. Did you mean 'typeof User'?

9 const myFunc = (user: User) => {
                        ~~~~

Found 1 error in app.vue:9

nuxt.config.ts:

export default defineNuxtConfig({
  devtools: { enabled: true },
  imports: {
    dirs: [
        'common/**/*.ts',
    ]
  }
})

user.ts:

export enum User {
  ADMIN = 'admin',
  USER = 'user',
}

app.vue

<template>
  <div>My app</div>
  <button @click="myFunc(User.ADMIN)">My button</button>
</template>

<script setup lang="ts">
// import { User } from './common/types/user';

const myFunc = (user: User) => {
  if (user === User.ADMIN) {
    console.log('admin');
  } else {
    console.log('user');
  }

  console.log(user);
};
</script>

If I add the import manually then typechecker does not complain ๐Ÿคท๐Ÿปโ€โ™‚๏ธ

import { User } from './common/types/user';

Additional context

No response

Logs

No response

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-node v4
  • codecov/codecov-action v4
npm
package.json
  • @rollup/pluginutils ^5.1.0
  • acorn ^8.12.1
  • escape-string-regexp ^5.0.0
  • estree-walker ^3.0.3
  • fast-glob ^3.3.2
  • local-pkg ^0.5.0
  • magic-string ^0.30.11
  • mlly ^1.7.1
  • pathe ^1.1.2
  • pkg-types ^1.1.3
  • scule ^1.3.0
  • strip-literal ^2.1.0
  • unplugin ^1.12.1
  • @antfu/eslint-config ^2.25.0
  • @types/estree ^1.0.5
  • @types/node ^22.2.0
  • @vitest/coverage-v8 ^2.0.5
  • bumpp ^9.4.2
  • conventional-changelog-cli ^5.0.0
  • eslint ^9.9.0
  • h3 ^1.12.0
  • jquery ^3.7.1
  • lit ^3.2.0
  • typescript ^5.5.4
  • unbuild ^2.0.0
  • vitest ^2.0.5
  • vue-tsc ^2.0.29
  • pnpm 9.7.0
playground/package.json
  • vue ^3.4.37
  • @vitejs/plugin-vue ^5.1.2
  • typescript ^5.5.4
  • vite ^5.4.0
  • vite-plugin-inspect ^0.8.5

  • Check this box to trigger a request for Renovate to run again on this repository

Support for plain typescript

Describe the feature

Correct me if I am wrong, but currently the module can only be used with vuejs, webpack and rollup. I have used it with vuejs in the past and would like to use it on my typescript api projects.

Additional information

  • Would you be willing to help implement this feature?

ESLint Plugin?

Describe the feature

One downside of auto-import is that some people would be concerned about the implicitness and uncertainty of where a function has been imported.

Wonder if we can come up with an optional eslint plugin that automatically inserts the import statement into the file.

Unlike the IDE auto-insertion that often injects the wrong path, and only available when you are typing that entry or explicitly clicking on the entry. Unimport maintains a list of imports with unique names, so that you always get the correct path. Meanwhile, with an ESLint Plugin, you can run it with a CLI and even filter the files you want it to enable. Combined with rules like https://www.npmjs.com/package/eslint-plugin-unused-imports, you can get autofix when you add or remove functions. Make the import statements almost fully automated.

Additional information

  • Would you be willing to help implement this feature?

Some imports in comments are taken into account

Environment

The issue has been reproduced in the following environment.

Reproduction

The simplest reproduction could look like this:

import { createUnimport } from 'unimport'

const { injectImports } = createUnimport({
  imports: [{ name: 'store', from: 'module-store' }],
  virtualImports: ['#imports'],
})

const input = "// import { store } from '#imports'"

const { code } = await injectImports(input)

console.log(code)

// import { store } from 'module-store';
// //

While, a more realistic reproduction would look like this:

import { createUnimport } from 'unimport'

const { injectImports } = createUnimport({
  imports: [{ name: 'store', from: 'module-store' }],
  virtualImports: ['#imports'],
})

const input = `export const store = {
  /**
   * @example
   * import { store } from '#imports'
   * store.fetch()
   */
  fetch: () => {}
}`

const { code } = await injectImports(input)

console.log(code)
// import { store } from 'module-store';
// export const store = {
//   /**
//    * @example
//    * * store.fetch()
//    */
//   fetch: () => {}
// }

Describe the bug

When unimport is given code with comments that include imports from virtual modules, those comments are taken into account to know whether imports should be injected or not.

In the reproduction above, we can see two things:

  1. The import from the comment section is removed.
  2. A new regular import is added at the top of the file.

In this specific scenario where comments are used to showcase how to use this piece of code, the result code will crash if executed. Indeed, there are now two variables with the same name:

  1. One from the import (import { store } from '#imports').
  2. One from the original code (const store).

From my understanding, I would expect imports in comments not to be taken into account when figuring out whether imports should be injected or not.

Additional context

I tracked this issue down from a Nuxt application where I first encountered the issue.

Logs

No response

Add WritableComputedRef as preset type for vuejs

Describe the feature

Hi,
though vuejs' computed can return ComputedRef and WritableComputedRef, I'd expect those two to be a preset return type as well. (corresponding PR incoming)

Additional information

  • Would you be willing to help implement this feature?

AST Parsing Mode

Describe the feature

RegExp is fast, but there would be so many edge cases that can't be solved properly. I think we could introduce an optional AST parsing mode to have the most accurate result, for ppl who willing to sacrifice a bit of performance to opt-in.

Additional information

  • Would you be willing to help implement this feature?

Bug: nested quotes

Hi! Great library.

I've encountered an issue with detecting usage of autoimported variables. If there's nested quotes (some quotes inside template literal), autoimported vars won't be detected and autoimport won't happen. Consider following example (assuming tc should be autoimported):

// Leave one line below uncommented
// const str = `${tc.log1()}`; // works
const str = `'${tc.log1()}'`; // doesnt work
// const str = `"${tc.log1()}"`; // doesnt work
// const str = `${`test${tc.log1()}`}`; // doesnt work

document.querySelector('#app').innerHTML = `
  <h1>Hello Vite! ${str}</h1>
`;

Full repro: https://stackblitz.com/edit/vite-hmbiei?file=main.js (it will crash when any line with "doesnt work" is uncommented)

Opt-out for auto-import

Describe the feature

The auto-import feature is convenient to use but sometimes could be confusing when users accidentally introduce circular auto-import references for accidentally introducing unnecessary references to some modules. Being about to opt-out auto-import for some modules could help to make some parts better organized.

Here are a few raw ideas:

1. Magic comments

We could do a quick RegExp check in the transforming phase to have fine-grained opt-out of some modules:

// @imports-disable
// @unimport-disable

2. Configuration

I guess it's already possible by setting the exclude options to exclude by globs.

Unimport({
  exclude: [
    'composables/**'
  ]
}

The issue we could need to solve might be to opt-out of the global TypeScript declarations for those modules.

3. Auto-injected magic comments

Taking it a bit further, we might do automatic import injection. We could have a comment marking the module as:

// @unimport-auto-inject
import { foo } from './foo'

And once you used a new import from the auto-import registry, let say bar:

// @unimport-auto-inject
import { foo } from './foo'

console.log(bar)

In development mode, we could inject the bar import automatically. Once we save the file, unimport will see the new usage communing and inject it like this:

// @unimport-auto-inject
+ import { bar } from './bar' // auto injected on save
import { foo } from './foo'

console.log(bar)

This way, it can help users make clear what and where the imports are auto-imported without worrying them too much.

Additional information

  • Would you be willing to help implement this feature?

Duplicate import warning when linking to a package

Environment

Node v18.16.0, Nuxt 3.7.1, Unimport 3.3.0

Reproduction

In v3.3.0 both the .d.ts and .mjs files are being imported from a linked package, causing import warnings.

Describe the bug

I have a nuxt module that registers a directory of composables for auto-import. It works fine when installed to node_modules, but as of [email protected] there is now a warning that occurs whens the module is linked.

Duplicated imports "useLog", the one from "[path to package]/dist/runtime/composables/core/useLog.d.ts" has been ignored

It looks like scanFilesFromDir should be ignoring the .d.ts files, but it doesn't work when the package is linked.

Additional context

No response

Logs

No response

`toExports` strips anything that look like an extension from package names

Environment

unimport: 3.0.11
node: v18.16.1

Reproduction

I raised this issue initially in Nuxt but soon realised the issue appears to come from this package.

nuxt/nuxt#23930

When using toExports with any export name containing anything that looks like an extension such as chart.js the issue presents.

Describe the bug

The issue is caused by:

name = name.replace(/\.[a-z]+$/, '')

This attempts to strip anything that looks like an extension from the name resulting in the incorrectly generated import from something like chart.js of just chart.

As a temporary workaround you can simply change it to chart.JS which avoids this regex matching. However this may also be an issue that this extension stripping should perhaps not be case-sensitive?

Not sure how to achieve this but the extension stripping should never be done on packages. Could we perhaps change the matcher to only concern itself with something which starts with ./ or a multi part filepath always ignoring the first segment?

Additional context

No response

Logs

No response

Add eslint-disable and prettier-ignore

Describe the feature

I believe these two annotations should be added at the top of the generated d.ts file to prevent conflicts with the project configuration.

Additional information

  • Would you be willing to help implement this feature?

Support for custom template files

Describe the feature

Vue allows for easily making use of custom template files (SFCs). In Stacks, we are experimenting with .stx files, which, essentially, are *.vue files with access to a bunch of auto-imported APIs.

The issue I am facing is that, as seen in the attached screenshot, onMounted() is an auto-imported API, but it's not accessible inside .stx files. If changed to HelloWorld.vue, it works.

Screenshot 2023-12-30 at 3 48 16โ€ฏPM

Any tips appreciated, as I am still trying to make sense of it ๐Ÿ™‚

Additional information

  • Would you be willing to help implement this feature?

matchRE regexp is not as expected.

Bug scene:
When I use unplugin-auto-import with vitest, and I execute obj.fit() in page, vite throw an error about can not use vitest in browser env.

Possible question:
When get identifiers in function detectImports,
it will resolve a string which likes obj.fit(), to an unexpected result as ["obj", "it"],
then it leads to the page imports the vitest, so the error occurs.

Possible solution:
If we don't take care of the keyword after dot,
maybe we can change matchRE regexp to /(?<![\w_$/).])([\w_$]+)\s*(?:[(.)[\]};+*&|<>,\n-])/g`;

Support export * without as

I really wish to be able to use export * from 'foo'. By looking at implemented tests, I assume this is currently not possible. It doesn't seem like a rare use-case, and as as is already optional, I don't see a reason to not support it.

Support for Astro JS

Describe the feature

I have tried using unimport with Astro JS. The plugin works perfectly well in .js(x)- and .ts(x)-files, but not in .astro-files. It simply says X is not defined. I have tried investigating the issue, but I have been unable to find and explanation thus far. Maybe someone else will be able to implement a solution.

Additional information

  • Would you be willing to help implement this feature?

`scanDirs` is not respecting the priority order of auto-imports

I am wondering why the current implementation of the scanDirExports is sorting the list of files after normalizing them. This is a major drawback as it does not allow you to set an explicit order of directories to scan and therefore of exports to override in case there's another one.

Example

When using Nuxt 3 auto-imports, I would expect this option:

imports: {
   dirs: ['foo', 'bar']
}

to let exports from bar override exports from foo, but since the filenames are sorted, exports from foo will always override exports from bar.

I can make a simple PR to prevent that sorting but I'm not exactly sure why it was there in the first place?

Thanks for your amazing work ๐Ÿ™

Error: EISDIR: illegal operation on a directory, read

Environment

Cloned repository on Windows 10 22H2 running Node v16.17.0

Reproduction

Change playground/composables/nested/index.ts to

export default function () {
  return 'from nested composables'
}

+ export * from './bar'

Describe the bug

export async function scanExports (filepath: string, seen = new Set<string>()): Promise<Import[]> {
if (seen.has(filepath)) {
// eslint-disable-next-line no-console
console.warn(`[unimport] "${filepath}" is already scanned, skipping`)
return []
}
seen.add(filepath)
const imports: Import[] = []
const code = await readFile(filepath, 'utf-8')

scanExports is likely to assume that filepath is indeed a filepath while it can be a directory, and so readFile fails for the above example where the filepath is playground/composables/nested/bar (with no file extension lookup available for it).

Additional context

Options I can think of:

  1. Check if equivalent /index exists.

if (existsSync(`${subfilepath}${ext}`)) {
subfilepath = `${subfilepath}${ext}`
break
}

if (existsSync(`${subfilepath}${ext}`)) {
  subfilepath = `${subfilepath}${ext}`
  break
+} else if (existsSync(`${subfilepath}/index${ext}`)) {
+  // 'foo' is a directory
+  subfilepath = `${subfilepath}/index${ext}`
+  break
+}
  1. I also believed that recursion wouldn't be required, but rather forward the imports. #216 (comment)

imports.push(...await scanExports(subfilepath, seen))

- imports.push(...await scanExports(subfilepath, seen))
+ imports.push({ name: '*', from: subfilepath })

Logs

No response

Support class extends

Describe the feature

For example:

class Foo extends Bar {}

Bar is registered but not auto-imported.

Linked issue: unplugin/unplugin-auto-import#301

I'd like to implement but I need some time to read the code :(

Additional information

  • Would you be willing to help implement this feature?

Don't camel-case default exports if they're already in correct case

Describe the bug

In a Nuxt 3 project I am trying to use the following config to make SFC components auto-importable in JS code:

export default defineNuxtConfig({
  imports: {
    dirs: ['components/**/*'],
  }

This almost works, but the components have to be referenced with camel-case names instead of their original pascal-case names, e.g. (from .nuxt/types/imports.d.ts):

const pageFooter: typeof import('../../components/PageFooter')['default']

This is caused by the use of camelCase() in this line here:

imports.push({ name: 'default', as: camelCase(name), from: filepath })

I looked at scule and it appears to split at '-', '_', '/', '.' to do the transformation:
https://github.com/unjs/scule/blob/249072ac10d1f441a23eb9df7bcb1bfc1e13d419/src/index.ts#L4

I'd like to suggest a change where the name is first inspected, and only if it contains any of these characters, will it be transformed using camelCase(). Otherwise it is passed on unmodified:

// Only camelize name if it contains separators by which scule would split,
// see STR_SPLITTERS: https://github.com/unjs/scule/blob/main/src/index.ts
const as = /[-_.]/.test(name) ? camelCase(name) : name
imports.push({ name: 'default', as, from: filepath })

Note that there is no need to check for / since it's only a file-name, not a path, at this point.

Auto-import fails when a identifier is the same as a name to be imported

Environment

unimport version: v3.3.0
node.js version: v18.16.0

Reproduction

import { createUnimport } from 'unimport'

const code = `
{
  const fn = () => {};
};

fn();
`

const { injectImports } = createUnimport({
  imports: [{ name: 'fn', from: 'module' }]
})

const { imports } = await injectImports(code)
console.log(imports)

Describe the bug

unimport/src/context.ts

Lines 247 to 256 in 28cf011

// Remove those already defined
for (const regex of excludeRE) {
for (const match of strippedCode.matchAll(regex)) {
const segments = [...match[1]?.split(separatorRE) || [], ...match[2]?.split(separatorRE) || []]
for (const segment of segments) {
const identifier = segment.replace(importAsRE, '').trim()
occurrenceMap.delete(identifier)
}
}
}

Before Remove those already defined, the value of occurrenceMap is { size:1, [{ "fn" => 30 }] }, where fn refers to the function which is called outside of the block scope.

While run into the for loop, strippedCode will match regexp /\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gs, and matching result is [ "const fn =", "fn" ], where fn refers to the function defined inside the block scope. So occurrenceMap.delete(identifier) will be executed, occurrenceMap will be cleared, and finally no import statement will be prepended to the code.

Seems in this situation, regexp matching is not enough, and lexical analysis may be needed?

Additional context

No response

Logs

No response

Vue template imports fail when variable is prefixed with `$`

Environment


  • Operating System: Linux
  • Node Version: v18.18.0
  • Nuxt Version: 3.8.2
  • CLI Version: 3.10.0
  • Nitro Version: 2.8.0
  • Package Manager: [email protected]
  • Builder: -
  • User Config: devtools
  • Runtime Modules: -
  • Build Modules: -

Reproduction

https://stackblitz.com/edit/nuxt-issues-24422

Describe the bug

When importing a variable like $myValue, it is not accessible in the Vue template.

Interestingly, the types are set/augmented correctly ๐Ÿค”

Additional context

nuxt/nuxt#24422

Logs

No response

Add ExtractPropTypes to exported types in vue preset

Describe the feature

Looking into the exported types of Vue, I noticed the absence of the 'ExportPropTypes' export. Is there a specific reason for not including this or other types? Should I manually add an import for this type from Vue in my 'unplugin-auto-import' configuration instead?

src/presets/vue.ts

  // types
  ...[
    'Component',
    'ComponentPublicInstance',
    'ComputedRef',
    'InjectionKey',
    'PropType',
    'Ref',
    'VNode',
    'WritableComputedRef'
  ].map(name => ({ name, type: true }))

Thanks in advance!

Additional information

  • Would you be willing to help implement this feature?

Import groups / namespaces

Describe the feature

Automatic imports are nice, but sometimes you don't want to clutter your virtual global scope with a lot of different things that share something in common. It would be great if Unimport could help you in situations like this.

Imagine a situation where you have a folder messages where each file would contain its own localisable message declarations exported as defaults:

// messages/page-titles.ts
export default defineMessages({
  projects: {
    id: 'page.projects.title',
    defaultMessage: 'Projects',
  },
})
// messages/errors.ts
export default defineMessages({
  notFound: {
    id: 'error.not-found',
    defaultMessage: 'Resource not found',
  },
})
// messages/utils.ts
export function getWorldGreeting() {
  return defineMessage({
    id: 'greetings.world',
    defaultMessage: 'Hello, world!',
  })
}

You don't really want to import each file separately, since pageTitles and errors are quite confusing. Nor do you want to rely on some naming conventions (like having files named like errors-messages to keep it clean.

In this case you'd likely prefer to have a globalMessages namespace, that would've contained all the imports than Unimport discovered, like pageTitles, errors, and anything else. It would also tree-shaking, as if you've done a specific import rather than imported everything at once.

To do so manually without Unimport right now you can make a barrel file:

// messages/index.barrel.ts
import pageTitles from "./page-titles.ts"
import errors from "./errors.ts"
export * from "./utils.ts"
export { pageTitles, errors }

And then the file that would export that barrel:

// messages/index.ts
export * as globalMessages from "./index.barrel.ts";

Now you can import { globalMessages } from '~/messages'. You can also add this to your Unimport.

But what if Unimport could group imports like this automatically for you?

You'd add a scan option:

unimport.vite({
  dirs: [
    './utils/*',
    { from: './messages/*', as: 'globalMessages' },
  ],
})

โ€ฆ and then would be able to use that through โ€˜variableโ€™:

// input: pages/projects/index.vue/<script setup>
console.log(formatMessage(globalMessages.pageTitles.projects))
declare global {
  const globalMessages: Readonly<{
    pageTitles: typeof import('../../messages/page-titles.ts')['default']
    errors: typeof import('../../messages/errors.ts')['default']
    getWorldGreeting: typeof('../../messages/utils.ts')['getWorldGreeting']
  }>
}

โ€ฆ which would expand to something along the lines of:

// output: pages/projects/index.vue/<script setup>
import pageTitles from '../../messages/page-titles.ts'
console.log(formatMessage(pageTitles.projects))

It may also work with other language features like destructuring, as long as it's deterministic (did you know that something like this would blow up tree-shaking in rollup?):

// src/a.js
const { pageTitles: { projects: projectsTitle } } = globalMessages
// src/a.js [transformed]
import pageTitles from '../../messages/page-titles.ts'
const { projects: projectsTitle } = pageTitles

Additional information

  • Would you be willing to help implement this feature?

error with @vueuse/core preset

I using this lib with Vite as

  const ctx = createUnimport({
    presets: ['vue', '@vueuse/core'],
    addons: { vueTemplate: true },
  })

and this configuration gives me

Error
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
  at __node_internal_captureLargerStackTrace (node:internal/errors:477:5)
  at new NodeError (node:internal/errors:388:5)
  at __node_internal_ (node:internal/fs/utils:673:11)
  at __node_internal_ (node:internal/fs/utils:685:3)
  at Object.openSync (node:fs:591:10)
  at Object.readFileSync (node:fs:467:35)
  at vueuseCore (/Users/amaurytobias/garsa/garsa-pdf/node_modules/.pnpm/[email protected][email protected]/node_modules/unimport/dist/chunks/context.cjs:311:41)
  at /Users/amaurytobias/garsa/garsa-pdf/node_modules/.pnpm/[email protected][email protected]/node_modules/unimport/dist/chunks/context.cjs:547:16
  at Array.flatMap (<anonymous>)
  at resolveBuiltinPresets (/Users/amaurytobias/garsa/garsa-pdf/node_modules/.pnpm/[email protected][email protected]/node_modules/unimport/dist/chunks/context.cjs:544:18)
  at createUnimport (/Users/amaurytobias/garsa/garsa-pdf/node_modules/.pnpm/[email protected][email protected]/node_modules/unimport/dist/chunks/context.cjs:629:29)
  at <anonymous> (/Users/amaurytobias/garsa/garsa-pdf/packages/builder/utils/kit.ts:324:15)
  at Object.<anonymous> (/Users/amaurytobias/garsa/garsa-pdf/node_modules/.pnpm/[email protected][email protected]/node_modules/unplugin/dist/index.js:4:688)
  at writeTypes (/Users/amaurytobias/garsa/garsa-pdf/packages/builder/utils/prepare.ts:130:32)
  at Object.invoke (/Users/amaurytobias/garsa/garsa-pdf/packages/builder/commands/prepare.ts:18:5)
  at _main (/Users/amaurytobias/garsa/garsa-pdf/packages/builder/cli.ts:18:18) {
code: 'ERR_INVALID_ARG_TYPE'
}

On unplugin-auto-import the @vueuse/core preset is different on the lines: 14:24

(unimport)[https://github.com/unjs/unimport/blob/main/src/presets/vueuse-core.ts]

 const path = resolveModule('@vueuse/core/indexes.json')
const indexesJson = JSON.parse(readFileSync(path!, 'utf-8'))
_cache = defineUnimportPreset({
    from: '@vueuse/core',
    imports: indexesJson
      .functions
      .filter((i: any) => ['core', 'shared'].includes(i.package))
      .map((i: any) => i.name as string)
      // only include functions with 4 characters or more
      .filter((i: string) => i && i.length >= 4 && !excluded.includes(i))
})

unplugin-auto-import

const corePath = resolveModule('@vueuse/core') || process.cwd()
const path = resolveModule('@vueuse/core/indexes.json')
    || resolveModule('@vueuse/metadata/index.json')
    || resolveModule('@vueuse/metadata/index.json', { paths: [corePath] })
 indexesJson = JSON.parse(readFileSync(path!, 'utf-8'))

idk if this can resolve the issue.

Support import `dirs` within core

Describe the feature

While working on unjs/nitro#866 i noticed that dirs option is only supported for unimport plugin but not unimport core and for generating types, it should be manually integrated with scanDirExports and modifyDynamicImports (there might be better ways no ideas).

it would be nice if we support it built-in to avoid workaround.

Reproduction: https://stackblitz.com/edit/node-x74ruz?file=index.mjs,utils%2Ftest.ts

(PS: Small unrelated bug i found generateTypeDeclarations is not stripping .ts from paths resulting into ts issues)

Additional information

  • Would you be willing to help implement this feature?

Group generated types by folder

Describe the feature

Hi Unimport team.

I'm a relatively new Nuxt 3 user, and one thing that always foxes me is auto-imports.

Although it's great that Nuxt auto-imports, the down-side is I don't know what is available, what or where it's from, or what package it belongs to. Sometimes I just look in the imports.d.ts file just to see, but it's just a big list of names.

However, if the declarations were grouped by folder, I think it would be a nice hint for those of us looking behind the curtain.

I wrote a quick and dirty node script to see what it might look like, and I think it's super helpful already:

// Generated by auto imports
export {}
declare global {
  // ../../node_modules/@unhead/vue
  const injectHead: typeof import('../../node_modules/@unhead/vue')['injectHead']
  const useHead: typeof import('../../node_modules/@unhead/vue')['useHead']
  const useHeadSafe: typeof import('../../node_modules/@unhead/vue')['useHeadSafe']
  const useSeoMeta: typeof import('../../node_modules/@unhead/vue')['useSeoMeta']
  const useServerHead: typeof import('../../node_modules/@unhead/vue')['useServerHead']
  const useServerHeadSafe: typeof import('../../node_modules/@unhead/vue')['useServerHeadSafe']
  const useServerSeoMeta: typeof import('../../node_modules/@unhead/vue')['useServerSeoMeta']

  // ../../node_modules/nuxt/dist/app
  const abortNavigation: typeof import('../../node_modules/nuxt/dist/app')['abortNavigation']
  const addRouteMiddleware: typeof import('../../node_modules/nuxt/dist/app')['addRouteMiddleware']
  const cancelIdleCallback: typeof import('../../node_modules/nuxt/dist/app')['cancelIdleCallback']
  const clearError: typeof import('../../node_modules/nuxt/dist/app')['clearError']
  const clearNuxtData: typeof import('../../node_modules/nuxt/dist/app')['clearNuxtData']
  const clearNuxtState: typeof import('../../node_modules/nuxt/dist/app')['clearNuxtState']
  const createError: typeof import('../../node_modules/nuxt/dist/app')['createError']
  const defineAppConfig: typeof import('../../node_modules/nuxt/dist/app')['defineAppConfig']
  const defineNuxtComponent: typeof import('../../node_modules/nuxt/dist/app')['defineNuxtComponent']
  const defineNuxtLink: typeof import('../../node_modules/nuxt/dist/app')['defineNuxtLink']
  const defineNuxtPlugin: typeof import('../../node_modules/nuxt/dist/app')['defineNuxtPlugin']
  const defineNuxtRouteMiddleware: typeof import('../../node_modules/nuxt/dist/app')['defineNuxtRouteMiddleware']
  const definePayloadPlugin: typeof import('../../node_modules/nuxt/dist/app')['definePayloadPlugin']
  const definePayloadReducer: typeof import('../../node_modules/nuxt/dist/app')['definePayloadReducer']
  const definePayloadReviver: typeof import('../../node_modules/nuxt/dist/app')['definePayloadReviver']
  const isNuxtError: typeof import('../../node_modules/nuxt/dist/app')['isNuxtError']
  const isPrerendered: typeof import('../../node_modules/nuxt/dist/app')['isPrerendered']
  const loadPayload: typeof import('../../node_modules/nuxt/dist/app')['loadPayload']
  const navigateTo: typeof import('../../node_modules/nuxt/dist/app')['navigateTo']
  const onNuxtReady: typeof import('../../node_modules/nuxt/dist/app')['onNuxtReady']
  const prefetchComponents: typeof import('../../node_modules/nuxt/dist/app')['prefetchComponents']
  const preloadComponents: typeof import('../../node_modules/nuxt/dist/app')['preloadComponents']
  const preloadPayload: typeof import('../../node_modules/nuxt/dist/app')['preloadPayload']
  const preloadRouteComponents: typeof import('../../node_modules/nuxt/dist/app')['preloadRouteComponents']
  const refreshNuxtData: typeof import('../../node_modules/nuxt/dist/app')['refreshNuxtData']
  const reloadNuxtApp: typeof import('../../node_modules/nuxt/dist/app')['reloadNuxtApp']
  const requestIdleCallback: typeof import('../../node_modules/nuxt/dist/app')['requestIdleCallback']
  const setPageLayout: typeof import('../../node_modules/nuxt/dist/app')['setPageLayout']
  const setResponseStatus: typeof import('../../node_modules/nuxt/dist/app')['setResponseStatus']
  const showError: typeof import('../../node_modules/nuxt/dist/app')['showError']
  const updateAppConfig: typeof import('../../node_modules/nuxt/dist/app')['updateAppConfig']
  const useAppConfig: typeof import('../../node_modules/nuxt/dist/app')['useAppConfig']
  const useAsyncData: typeof import('../../node_modules/nuxt/dist/app')['useAsyncData']
  const useCookie: typeof import('../../node_modules/nuxt/dist/app')['useCookie']
  const useError: typeof import('../../node_modules/nuxt/dist/app')['useError']
  const useFetch: typeof import('../../node_modules/nuxt/dist/app')['useFetch']
  const useLazyAsyncData: typeof import('../../node_modules/nuxt/dist/app')['useLazyAsyncData']
  const useLazyFetch: typeof import('../../node_modules/nuxt/dist/app')['useLazyFetch']
  const useNuxtApp: typeof import('../../node_modules/nuxt/dist/app')['useNuxtApp']
  const useNuxtData: typeof import('../../node_modules/nuxt/dist/app')['useNuxtData']
  const useRequestEvent: typeof import('../../node_modules/nuxt/dist/app')['useRequestEvent']
  const useRequestFetch: typeof import('../../node_modules/nuxt/dist/app')['useRequestFetch']
  const useRequestHeaders: typeof import('../../node_modules/nuxt/dist/app')['useRequestHeaders']
  const useRequestURL: typeof import('../../node_modules/nuxt/dist/app')['useRequestURL']
  const useRoute: typeof import('../../node_modules/nuxt/dist/app')['useRoute']
  const useRouter: typeof import('../../node_modules/nuxt/dist/app')['useRouter']
  const useRuntimeConfig: typeof import('../../node_modules/nuxt/dist/app')['useRuntimeConfig']
  const useState: typeof import('../../node_modules/nuxt/dist/app')['useState']

  // ../../node_modules/nuxt/dist/app/compat/vue-demi
  const isVue2: typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue2']
  const isVue3: typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue3']

  // ../../node_modules/nuxt/dist/pages/runtime/composables
  const definePageMeta: typeof import('../../node_modules/nuxt/dist/pages/runtime/composables')['definePageMeta']

  // ../../node_modules/vue
  const computed: typeof import('../../node_modules/vue')['computed']
  const customRef: typeof import('../../node_modules/vue')['customRef']
  const defineAsyncComponent: typeof import('../../node_modules/vue')['defineAsyncComponent']
  const defineComponent: typeof import('../../node_modules/vue')['defineComponent']
  const defineModel: typeof import('../../node_modules/vue')['defineModel']
  const defineOptions: typeof import('../../node_modules/vue')['defineOptions']
  const defineSlots: typeof import('../../node_modules/vue')['defineSlots']
  const effect: typeof import('../../node_modules/vue')['effect']
  const effectScope: typeof import('../../node_modules/vue')['effectScope']
  const getCurrentInstance: typeof import('../../node_modules/vue')['getCurrentInstance']
  const getCurrentScope: typeof import('../../node_modules/vue')['getCurrentScope']
  const h: typeof import('../../node_modules/vue')['h']
  const hasInjectionContext: typeof import('../../node_modules/vue')['hasInjectionContext']
  const inject: typeof import('../../node_modules/vue')['inject']
  const isProxy: typeof import('../../node_modules/vue')['isProxy']
  const isReactive: typeof import('../../node_modules/vue')['isReactive']
  const isReadonly: typeof import('../../node_modules/vue')['isReadonly']
  const isRef: typeof import('../../node_modules/vue')['isRef']
  const isShallow: typeof import('../../node_modules/vue')['isShallow']
  const markRaw: typeof import('../../node_modules/vue')['markRaw']
  const mergeModels: typeof import('../../node_modules/vue')['mergeModels']
  const nextTick: typeof import('../../node_modules/vue')['nextTick']
  const onActivated: typeof import('../../node_modules/vue')['onActivated']
  const onBeforeMount: typeof import('../../node_modules/vue')['onBeforeMount']
  const onBeforeUnmount: typeof import('../../node_modules/vue')['onBeforeUnmount']
  const onBeforeUpdate: typeof import('../../node_modules/vue')['onBeforeUpdate']
  const onDeactivated: typeof import('../../node_modules/vue')['onDeactivated']
  const onErrorCaptured: typeof import('../../node_modules/vue')['onErrorCaptured']
  const onMounted: typeof import('../../node_modules/vue')['onMounted']
  const onRenderTracked: typeof import('../../node_modules/vue')['onRenderTracked']
  const onRenderTriggered: typeof import('../../node_modules/vue')['onRenderTriggered']
  const onScopeDispose: typeof import('../../node_modules/vue')['onScopeDispose']
  const onServerPrefetch: typeof import('../../node_modules/vue')['onServerPrefetch']
  const onUnmounted: typeof import('../../node_modules/vue')['onUnmounted']
  const onUpdated: typeof import('../../node_modules/vue')['onUpdated']
  const provide: typeof import('../../node_modules/vue')['provide']
  const proxyRefs: typeof import('../../node_modules/vue')['proxyRefs']
  const reactive: typeof import('../../node_modules/vue')['reactive']
  const readonly: typeof import('../../node_modules/vue')['readonly']
  const ref: typeof import('../../node_modules/vue')['ref']
  const resolveComponent: typeof import('../../node_modules/vue')['resolveComponent']
  const shallowReactive: typeof import('../../node_modules/vue')['shallowReactive']
  const shallowReadonly: typeof import('../../node_modules/vue')['shallowReadonly']
  const shallowRef: typeof import('../../node_modules/vue')['shallowRef']
  const toRaw: typeof import('../../node_modules/vue')['toRaw']
  const toRef: typeof import('../../node_modules/vue')['toRef']
  const toRefs: typeof import('../../node_modules/vue')['toRefs']
  const toValue: typeof import('../../node_modules/vue')['toValue']
  const triggerRef: typeof import('../../node_modules/vue')['triggerRef']
  const unref: typeof import('../../node_modules/vue')['unref']
  const useAttrs: typeof import('../../node_modules/vue')['useAttrs']
  const useCssModule: typeof import('../../node_modules/vue')['useCssModule']
  const useCssVars: typeof import('../../node_modules/vue')['useCssVars']
  const useModel: typeof import('../../node_modules/vue')['useModel']
  const useSlots: typeof import('../../node_modules/vue')['useSlots']
  const useTransitionState: typeof import('../../node_modules/vue')['useTransitionState']
  const watch: typeof import('../../node_modules/vue')['watch']
  const watchEffect: typeof import('../../node_modules/vue')['watchEffect']
  const watchPostEffect: typeof import('../../node_modules/vue')['watchPostEffect']
  const watchSyncEffect: typeof import('../../node_modules/vue')['watchSyncEffect']
  const withCtx: typeof import('../../node_modules/vue')['withCtx']
  const withDirectives: typeof import('../../node_modules/vue')['withDirectives']
  const withKeys: typeof import('../../node_modules/vue')['withKeys']
  const withMemo: typeof import('../../node_modules/vue')['withMemo']
  const withModifiers: typeof import('../../node_modules/vue')['withModifiers']
  const withScopeId: typeof import('../../node_modules/vue')['withScopeId']

  // ../../src/utils/config
  const image: typeof import('../../src/utils/config')['image']
  const link: typeof import('../../src/utils/config')['link']
  const meta: typeof import('../../src/utils/config')['meta']
  const script: typeof import('../../src/utils/config')['script']

  // ../../src/utils/data
  const isObject: typeof import('../../src/utils/data')['isObject']

  // ../../src/utils/env
  const isDev: typeof import('../../src/utils/env')['isDev']
  const isProd: typeof import('../../src/utils/env')['isProd']

  // ../../src/utils/text
  const markdown: typeof import('../../src/utils/text')['markdown']

  // ../vue-router
  const onBeforeRouteLeave: typeof import('../vue-router')['onBeforeRouteLeave']
  const onBeforeRouteUpdate: typeof import('../vue-router')['onBeforeRouteUpdate']
  const useLink: typeof import('../vue-router')['useLink']

}
// for type re-export
declare global {
  // @ts-ignore
  export type { Component, ComponentPublicInstance, ComputedRef, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode } from '../../node_modules/vue'
}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
  interface ComponentCustomProperties {
    // ../../node_modules/@unhead/vue
    readonly injectHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['injectHead']>
    readonly useHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useHead']>
    readonly useHeadSafe: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useHeadSafe']>
    readonly useSeoMeta: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useSeoMeta']>
    readonly useServerHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerHead']>
    readonly useServerHeadSafe: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerHeadSafe']>
    readonly useServerSeoMeta: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerSeoMeta']>

    // ../../node_modules/nuxt/dist/app
    readonly abortNavigation: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['abortNavigation']>
    readonly addRouteMiddleware: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['addRouteMiddleware']>
    readonly cancelIdleCallback: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['cancelIdleCallback']>
    readonly clearError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearError']>
    readonly clearNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearNuxtData']>
    readonly clearNuxtState: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearNuxtState']>
    readonly createError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['createError']>
    readonly defineAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineAppConfig']>
    readonly defineNuxtComponent: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtComponent']>
    readonly defineNuxtLink: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtLink']>
    readonly defineNuxtPlugin: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtPlugin']>
    readonly defineNuxtRouteMiddleware: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtRouteMiddleware']>
    readonly definePayloadPlugin: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadPlugin']>
    readonly definePayloadReducer: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadReducer']>
    readonly definePayloadReviver: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadReviver']>
    readonly isNuxtError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['isNuxtError']>
    readonly isPrerendered: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['isPrerendered']>
    readonly loadPayload: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['loadPayload']>
    readonly navigateTo: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['navigateTo']>
    readonly onNuxtReady: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['onNuxtReady']>
    readonly prefetchComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['prefetchComponents']>
    readonly preloadComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadComponents']>
    readonly preloadPayload: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadPayload']>
    readonly preloadRouteComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadRouteComponents']>
    readonly refreshNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['refreshNuxtData']>
    readonly reloadNuxtApp: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['reloadNuxtApp']>
    readonly requestIdleCallback: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['requestIdleCallback']>
    readonly setPageLayout: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['setPageLayout']>
    readonly setResponseStatus: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['setResponseStatus']>
    readonly showError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['showError']>
    readonly updateAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['updateAppConfig']>
    readonly useAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useAppConfig']>
    readonly useAsyncData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useAsyncData']>
    readonly useCookie: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useCookie']>
    readonly useError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useError']>
    readonly useFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useFetch']>
    readonly useLazyAsyncData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useLazyAsyncData']>
    readonly useLazyFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useLazyFetch']>
    readonly useNuxtApp: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useNuxtApp']>
    readonly useNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useNuxtData']>
    readonly useRequestEvent: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestEvent']>
    readonly useRequestFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestFetch']>
    readonly useRequestHeaders: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestHeaders']>
    readonly useRequestURL: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestURL']>
    readonly useRoute: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRoute']>
    readonly useRouter: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRouter']>
    readonly useRuntimeConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRuntimeConfig']>
    readonly useState: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useState']>

    // ../../node_modules/nuxt/dist/app/compat/vue-demi
    readonly isVue2: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue2']>
    readonly isVue3: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue3']>

    // ../../node_modules/nuxt/dist/pages/runtime/composables
    readonly definePageMeta: UnwrapRef<typeof import('../../node_modules/nuxt/dist/pages/runtime/composables')['definePageMeta']>

    // ../../node_modules/vue
    readonly computed: UnwrapRef<typeof import('../../node_modules/vue')['computed']>
    readonly customRef: UnwrapRef<typeof import('../../node_modules/vue')['customRef']>
    readonly defineAsyncComponent: UnwrapRef<typeof import('../../node_modules/vue')['defineAsyncComponent']>
    readonly defineComponent: UnwrapRef<typeof import('../../node_modules/vue')['defineComponent']>
    readonly defineModel: UnwrapRef<typeof import('../../node_modules/vue')['defineModel']>
    readonly defineOptions: UnwrapRef<typeof import('../../node_modules/vue')['defineOptions']>
    readonly defineSlots: UnwrapRef<typeof import('../../node_modules/vue')['defineSlots']>
    readonly effect: UnwrapRef<typeof import('../../node_modules/vue')['effect']>
    readonly effectScope: UnwrapRef<typeof import('../../node_modules/vue')['effectScope']>
    readonly getCurrentInstance: UnwrapRef<typeof import('../../node_modules/vue')['getCurrentInstance']>
    readonly getCurrentScope: UnwrapRef<typeof import('../../node_modules/vue')['getCurrentScope']>
    readonly h: UnwrapRef<typeof import('../../node_modules/vue')['h']>
    readonly hasInjectionContext: UnwrapRef<typeof import('../../node_modules/vue')['hasInjectionContext']>
    readonly inject: UnwrapRef<typeof import('../../node_modules/vue')['inject']>
    readonly isProxy: UnwrapRef<typeof import('../../node_modules/vue')['isProxy']>
    readonly isReactive: UnwrapRef<typeof import('../../node_modules/vue')['isReactive']>
    readonly isReadonly: UnwrapRef<typeof import('../../node_modules/vue')['isReadonly']>
    readonly isRef: UnwrapRef<typeof import('../../node_modules/vue')['isRef']>
    readonly isShallow: UnwrapRef<typeof import('../../node_modules/vue')['isShallow']>
    readonly markRaw: UnwrapRef<typeof import('../../node_modules/vue')['markRaw']>
    readonly mergeModels: UnwrapRef<typeof import('../../node_modules/vue')['mergeModels']>
    readonly nextTick: UnwrapRef<typeof import('../../node_modules/vue')['nextTick']>
    readonly onActivated: UnwrapRef<typeof import('../../node_modules/vue')['onActivated']>
    readonly onBeforeMount: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeMount']>
    readonly onBeforeUnmount: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeUnmount']>
    readonly onBeforeUpdate: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeUpdate']>
    readonly onDeactivated: UnwrapRef<typeof import('../../node_modules/vue')['onDeactivated']>
    readonly onErrorCaptured: UnwrapRef<typeof import('../../node_modules/vue')['onErrorCaptured']>
    readonly onMounted: UnwrapRef<typeof import('../../node_modules/vue')['onMounted']>
    readonly onRenderTracked: UnwrapRef<typeof import('../../node_modules/vue')['onRenderTracked']>
    readonly onRenderTriggered: UnwrapRef<typeof import('../../node_modules/vue')['onRenderTriggered']>
    readonly onScopeDispose: UnwrapRef<typeof import('../../node_modules/vue')['onScopeDispose']>
    readonly onServerPrefetch: UnwrapRef<typeof import('../../node_modules/vue')['onServerPrefetch']>
    readonly onUnmounted: UnwrapRef<typeof import('../../node_modules/vue')['onUnmounted']>
    readonly onUpdated: UnwrapRef<typeof import('../../node_modules/vue')['onUpdated']>
    readonly provide: UnwrapRef<typeof import('../../node_modules/vue')['provide']>
    readonly proxyRefs: UnwrapRef<typeof import('../../node_modules/vue')['proxyRefs']>
    readonly reactive: UnwrapRef<typeof import('../../node_modules/vue')['reactive']>
    readonly readonly: UnwrapRef<typeof import('../../node_modules/vue')['readonly']>
    readonly ref: UnwrapRef<typeof import('../../node_modules/vue')['ref']>
    readonly resolveComponent: UnwrapRef<typeof import('../../node_modules/vue')['resolveComponent']>
    readonly shallowReactive: UnwrapRef<typeof import('../../node_modules/vue')['shallowReactive']>
    readonly shallowReadonly: UnwrapRef<typeof import('../../node_modules/vue')['shallowReadonly']>
    readonly shallowRef: UnwrapRef<typeof import('../../node_modules/vue')['shallowRef']>
    readonly toRaw: UnwrapRef<typeof import('../../node_modules/vue')['toRaw']>
    readonly toRef: UnwrapRef<typeof import('../../node_modules/vue')['toRef']>
    readonly toRefs: UnwrapRef<typeof import('../../node_modules/vue')['toRefs']>
    readonly toValue: UnwrapRef<typeof import('../../node_modules/vue')['toValue']>
    readonly triggerRef: UnwrapRef<typeof import('../../node_modules/vue')['triggerRef']>
    readonly unref: UnwrapRef<typeof import('../../node_modules/vue')['unref']>
    readonly useAttrs: UnwrapRef<typeof import('../../node_modules/vue')['useAttrs']>
    readonly useCssModule: UnwrapRef<typeof import('../../node_modules/vue')['useCssModule']>
    readonly useCssVars: UnwrapRef<typeof import('../../node_modules/vue')['useCssVars']>
    readonly useModel: UnwrapRef<typeof import('../../node_modules/vue')['useModel']>
    readonly useSlots: UnwrapRef<typeof import('../../node_modules/vue')['useSlots']>
    readonly useTransitionState: UnwrapRef<typeof import('../../node_modules/vue')['useTransitionState']>
    readonly watch: UnwrapRef<typeof import('../../node_modules/vue')['watch']>
    readonly watchEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchEffect']>
    readonly watchPostEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchPostEffect']>
    readonly watchSyncEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchSyncEffect']>
    readonly withCtx: UnwrapRef<typeof import('../../node_modules/vue')['withCtx']>
    readonly withDirectives: UnwrapRef<typeof import('../../node_modules/vue')['withDirectives']>
    readonly withKeys: UnwrapRef<typeof import('../../node_modules/vue')['withKeys']>
    readonly withMemo: UnwrapRef<typeof import('../../node_modules/vue')['withMemo']>
    readonly withModifiers: UnwrapRef<typeof import('../../node_modules/vue')['withModifiers']>
    readonly withScopeId: UnwrapRef<typeof import('../../node_modules/vue')['withScopeId']>

    // ../../src/utils/config
    readonly image: UnwrapRef<typeof import('../../src/utils/config')['image']>
    readonly link: UnwrapRef<typeof import('../../src/utils/config')['link']>
    readonly meta: UnwrapRef<typeof import('../../src/utils/config')['meta']>
    readonly script: UnwrapRef<typeof import('../../src/utils/config')['script']>

    // ../../src/utils/data
    readonly isObject: UnwrapRef<typeof import('../../src/utils/data')['isObject']>

    // ../../src/utils/env
    readonly isDev: UnwrapRef<typeof import('../../src/utils/env')['isDev']>
    readonly isProd: UnwrapRef<typeof import('../../src/utils/env')['isProd']>

    // ../../src/utils/text
    readonly markdown: UnwrapRef<typeof import('../../src/utils/text')['markdown']>

    // ../vue-router
    readonly onBeforeRouteLeave: UnwrapRef<typeof import('../vue-router')['onBeforeRouteLeave']>
    readonly onBeforeRouteUpdate: UnwrapRef<typeof import('../vue-router')['onBeforeRouteUpdate']>
    readonly useLink: UnwrapRef<typeof import('../vue-router')['useLink']>

  }
}
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    // ../../node_modules/@unhead/vue
    readonly injectHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['injectHead']>
    readonly useHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useHead']>
    readonly useHeadSafe: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useHeadSafe']>
    readonly useSeoMeta: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useSeoMeta']>
    readonly useServerHead: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerHead']>
    readonly useServerHeadSafe: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerHeadSafe']>
    readonly useServerSeoMeta: UnwrapRef<typeof import('../../node_modules/@unhead/vue')['useServerSeoMeta']>

    // ../../node_modules/nuxt/dist/app
    readonly abortNavigation: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['abortNavigation']>
    readonly addRouteMiddleware: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['addRouteMiddleware']>
    readonly cancelIdleCallback: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['cancelIdleCallback']>
    readonly clearError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearError']>
    readonly clearNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearNuxtData']>
    readonly clearNuxtState: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['clearNuxtState']>
    readonly createError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['createError']>
    readonly defineAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineAppConfig']>
    readonly defineNuxtComponent: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtComponent']>
    readonly defineNuxtLink: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtLink']>
    readonly defineNuxtPlugin: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtPlugin']>
    readonly defineNuxtRouteMiddleware: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['defineNuxtRouteMiddleware']>
    readonly definePayloadPlugin: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadPlugin']>
    readonly definePayloadReducer: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadReducer']>
    readonly definePayloadReviver: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['definePayloadReviver']>
    readonly isNuxtError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['isNuxtError']>
    readonly isPrerendered: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['isPrerendered']>
    readonly loadPayload: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['loadPayload']>
    readonly navigateTo: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['navigateTo']>
    readonly onNuxtReady: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['onNuxtReady']>
    readonly prefetchComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['prefetchComponents']>
    readonly preloadComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadComponents']>
    readonly preloadPayload: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadPayload']>
    readonly preloadRouteComponents: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['preloadRouteComponents']>
    readonly refreshNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['refreshNuxtData']>
    readonly reloadNuxtApp: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['reloadNuxtApp']>
    readonly requestIdleCallback: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['requestIdleCallback']>
    readonly setPageLayout: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['setPageLayout']>
    readonly setResponseStatus: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['setResponseStatus']>
    readonly showError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['showError']>
    readonly updateAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['updateAppConfig']>
    readonly useAppConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useAppConfig']>
    readonly useAsyncData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useAsyncData']>
    readonly useCookie: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useCookie']>
    readonly useError: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useError']>
    readonly useFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useFetch']>
    readonly useLazyAsyncData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useLazyAsyncData']>
    readonly useLazyFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useLazyFetch']>
    readonly useNuxtApp: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useNuxtApp']>
    readonly useNuxtData: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useNuxtData']>
    readonly useRequestEvent: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestEvent']>
    readonly useRequestFetch: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestFetch']>
    readonly useRequestHeaders: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestHeaders']>
    readonly useRequestURL: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRequestURL']>
    readonly useRoute: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRoute']>
    readonly useRouter: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRouter']>
    readonly useRuntimeConfig: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useRuntimeConfig']>
    readonly useState: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app')['useState']>

    // ../../node_modules/nuxt/dist/app/compat/vue-demi
    readonly isVue2: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue2']>
    readonly isVue3: UnwrapRef<typeof import('../../node_modules/nuxt/dist/app/compat/vue-demi')['isVue3']>

    // ../../node_modules/nuxt/dist/pages/runtime/composables
    readonly definePageMeta: UnwrapRef<typeof import('../../node_modules/nuxt/dist/pages/runtime/composables')['definePageMeta']>

    // ../../node_modules/vue
    readonly computed: UnwrapRef<typeof import('../../node_modules/vue')['computed']>
    readonly customRef: UnwrapRef<typeof import('../../node_modules/vue')['customRef']>
    readonly defineAsyncComponent: UnwrapRef<typeof import('../../node_modules/vue')['defineAsyncComponent']>
    readonly defineComponent: UnwrapRef<typeof import('../../node_modules/vue')['defineComponent']>
    readonly defineModel: UnwrapRef<typeof import('../../node_modules/vue')['defineModel']>
    readonly defineOptions: UnwrapRef<typeof import('../../node_modules/vue')['defineOptions']>
    readonly defineSlots: UnwrapRef<typeof import('../../node_modules/vue')['defineSlots']>
    readonly effect: UnwrapRef<typeof import('../../node_modules/vue')['effect']>
    readonly effectScope: UnwrapRef<typeof import('../../node_modules/vue')['effectScope']>
    readonly getCurrentInstance: UnwrapRef<typeof import('../../node_modules/vue')['getCurrentInstance']>
    readonly getCurrentScope: UnwrapRef<typeof import('../../node_modules/vue')['getCurrentScope']>
    readonly h: UnwrapRef<typeof import('../../node_modules/vue')['h']>
    readonly hasInjectionContext: UnwrapRef<typeof import('../../node_modules/vue')['hasInjectionContext']>
    readonly inject: UnwrapRef<typeof import('../../node_modules/vue')['inject']>
    readonly isProxy: UnwrapRef<typeof import('../../node_modules/vue')['isProxy']>
    readonly isReactive: UnwrapRef<typeof import('../../node_modules/vue')['isReactive']>
    readonly isReadonly: UnwrapRef<typeof import('../../node_modules/vue')['isReadonly']>
    readonly isRef: UnwrapRef<typeof import('../../node_modules/vue')['isRef']>
    readonly isShallow: UnwrapRef<typeof import('../../node_modules/vue')['isShallow']>
    readonly markRaw: UnwrapRef<typeof import('../../node_modules/vue')['markRaw']>
    readonly mergeModels: UnwrapRef<typeof import('../../node_modules/vue')['mergeModels']>
    readonly nextTick: UnwrapRef<typeof import('../../node_modules/vue')['nextTick']>
    readonly onActivated: UnwrapRef<typeof import('../../node_modules/vue')['onActivated']>
    readonly onBeforeMount: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeMount']>
    readonly onBeforeUnmount: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeUnmount']>
    readonly onBeforeUpdate: UnwrapRef<typeof import('../../node_modules/vue')['onBeforeUpdate']>
    readonly onDeactivated: UnwrapRef<typeof import('../../node_modules/vue')['onDeactivated']>
    readonly onErrorCaptured: UnwrapRef<typeof import('../../node_modules/vue')['onErrorCaptured']>
    readonly onMounted: UnwrapRef<typeof import('../../node_modules/vue')['onMounted']>
    readonly onRenderTracked: UnwrapRef<typeof import('../../node_modules/vue')['onRenderTracked']>
    readonly onRenderTriggered: UnwrapRef<typeof import('../../node_modules/vue')['onRenderTriggered']>
    readonly onScopeDispose: UnwrapRef<typeof import('../../node_modules/vue')['onScopeDispose']>
    readonly onServerPrefetch: UnwrapRef<typeof import('../../node_modules/vue')['onServerPrefetch']>
    readonly onUnmounted: UnwrapRef<typeof import('../../node_modules/vue')['onUnmounted']>
    readonly onUpdated: UnwrapRef<typeof import('../../node_modules/vue')['onUpdated']>
    readonly provide: UnwrapRef<typeof import('../../node_modules/vue')['provide']>
    readonly proxyRefs: UnwrapRef<typeof import('../../node_modules/vue')['proxyRefs']>
    readonly reactive: UnwrapRef<typeof import('../../node_modules/vue')['reactive']>
    readonly readonly: UnwrapRef<typeof import('../../node_modules/vue')['readonly']>
    readonly ref: UnwrapRef<typeof import('../../node_modules/vue')['ref']>
    readonly resolveComponent: UnwrapRef<typeof import('../../node_modules/vue')['resolveComponent']>
    readonly shallowReactive: UnwrapRef<typeof import('../../node_modules/vue')['shallowReactive']>
    readonly shallowReadonly: UnwrapRef<typeof import('../../node_modules/vue')['shallowReadonly']>
    readonly shallowRef: UnwrapRef<typeof import('../../node_modules/vue')['shallowRef']>
    readonly toRaw: UnwrapRef<typeof import('../../node_modules/vue')['toRaw']>
    readonly toRef: UnwrapRef<typeof import('../../node_modules/vue')['toRef']>
    readonly toRefs: UnwrapRef<typeof import('../../node_modules/vue')['toRefs']>
    readonly toValue: UnwrapRef<typeof import('../../node_modules/vue')['toValue']>
    readonly triggerRef: UnwrapRef<typeof import('../../node_modules/vue')['triggerRef']>
    readonly unref: UnwrapRef<typeof import('../../node_modules/vue')['unref']>
    readonly useAttrs: UnwrapRef<typeof import('../../node_modules/vue')['useAttrs']>
    readonly useCssModule: UnwrapRef<typeof import('../../node_modules/vue')['useCssModule']>
    readonly useCssVars: UnwrapRef<typeof import('../../node_modules/vue')['useCssVars']>
    readonly useModel: UnwrapRef<typeof import('../../node_modules/vue')['useModel']>
    readonly useSlots: UnwrapRef<typeof import('../../node_modules/vue')['useSlots']>
    readonly useTransitionState: UnwrapRef<typeof import('../../node_modules/vue')['useTransitionState']>
    readonly watch: UnwrapRef<typeof import('../../node_modules/vue')['watch']>
    readonly watchEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchEffect']>
    readonly watchPostEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchPostEffect']>
    readonly watchSyncEffect: UnwrapRef<typeof import('../../node_modules/vue')['watchSyncEffect']>
    readonly withCtx: UnwrapRef<typeof import('../../node_modules/vue')['withCtx']>
    readonly withDirectives: UnwrapRef<typeof import('../../node_modules/vue')['withDirectives']>
    readonly withKeys: UnwrapRef<typeof import('../../node_modules/vue')['withKeys']>
    readonly withMemo: UnwrapRef<typeof import('../../node_modules/vue')['withMemo']>
    readonly withModifiers: UnwrapRef<typeof import('../../node_modules/vue')['withModifiers']>
    readonly withScopeId: UnwrapRef<typeof import('../../node_modules/vue')['withScopeId']>

    // ../../src/utils/config
    readonly image: UnwrapRef<typeof import('../../src/utils/config')['image']>
    readonly link: UnwrapRef<typeof import('../../src/utils/config')['link']>
    readonly meta: UnwrapRef<typeof import('../../src/utils/config')['meta']>
    readonly script: UnwrapRef<typeof import('../../src/utils/config')['script']>

    // ../../src/utils/data
    readonly isObject: UnwrapRef<typeof import('../../src/utils/data')['isObject']>

    // ../../src/utils/env
    readonly isDev: UnwrapRef<typeof import('../../src/utils/env')['isDev']>
    readonly isProd: UnwrapRef<typeof import('../../src/utils/env')['isProd']>

    // ../../src/utils/text
    readonly markdown: UnwrapRef<typeof import('../../src/utils/text')['markdown']>

    // ../vue-router
    readonly onBeforeRouteLeave: UnwrapRef<typeof import('../vue-router')['onBeforeRouteLeave']>
    readonly onBeforeRouteUpdate: UnwrapRef<typeof import('../vue-router')['onBeforeRouteUpdate']>
    readonly useLink: UnwrapRef<typeof import('../vue-router')['useLink']>

  }
}

Think this is something you could build in to the generation function?

Additional information

  • Would you be willing to help implement this feature?

Playground does not work

Disclaimer: this is using npm.

When trying to run the playground (after an npm i), the server throws the following error:

[plugin:unimport] s.hasChanged is not a function
/Users/reinierkaper/personal/unimport/playground/src/main.ts
    at TransformContext.transform (file:///Users/reinierkaper/personal/unimport/playground/vite.config.ts.timestamp-1663630386798.mjs:1067:14)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async file:///Users/reinierkaper/personal/unimport/playground/node_modules/vite-plugin-inspect/dist/index.mjs:676:23
    at async Object.transform (file:///Users/reinierkaper/personal/unimport/playground/node_modules/vite/dist/node/chunks/dep-557f29e6.js:41102:30)
    at async loadAndTransform (file:///Users/reinierkaper/personal/unimport/playground/node_modules/vite/dist/node/chunks/dep-557f29e6.js:37364:29

System: MacOS 12.5.1
Browser: Chrome 105.0.5195.125
Node: 16.15.1
npm: 8.12.1

`scanImportsFromDir` fails to detect `subdir/index.{tsx|jsx}` files

Environment

  • Unimport: v3.7.1
  • Node: v18.16.1

Reproduction

https://github.com/aklinker1/unimport-tsx-bug

pnpm i
node index.mjs

Describe the bug

When components/index.ts exports a subdirectory with a index.tsx file in it, an error is throw (see logs below).

https://github.com/aklinker1/unimport-tsx-bug/blob/56985dab7724fae0c3e28f3801d6b3297bb2eed3/components/index.ts#L1

Same error is thrown if the file is components/Iframe/index.jsx.

There is a work-around, change the export in components/index.ts:

-export * from "./Iframe";
+export * from "./Iframe/index.tsx";

Additional context

This issue originates from: wxt-dev/wxt#440

I did some research into this and it appears we just need to add "tsx" and "jsx" to the file extensions array?

const FileExtensionLookup = [
'.mts',
'.cts',
'.ts',
'.mjs',
'.cjs',
'.js'
]

#229 fixed this for non-JSX files.

Logs

$ node index.mjs
node:internal/process/esm_loader:97
    internalBinding('errors').triggerUncaughtException(
                              ^

[Error: EISDIR: illegal operation on a directory, read] {
  errno: -21,
  code: 'EISDIR',
  syscall: 'read'
}

Node.js v18.16.1

Support for unjs stack in presets

Context

I am developing a web application in Nuxt. So, unjs/unimport has been very helpful. Thank you for developing it.

I often use the following two for developing web applications in Nuxt.

  • unjs/consola: Logger for Nuxt Server
  • unjs/h3: use in Nuxt Server

I would like to be able to use unjs stack from unimport presets, not only these two.

Design

There are two possible designs

  1. add unjs/* to each preset.

    • Advantage: easier for users to find from presets.
    • Disadvantage: presets will be bloated by the number of unjs stacks -> more than 50 files will make presets/ harder to maintain

    Example

    • consola -> presets/consola.ts
    • h3 -> presets/h3.ts.
presets: [
  {
    from: "consola",
    imports: [ "consola" ]
  },
  {
    from: "h3",
    imports: [ "EventHandler", "EventHandlerRequest", "readBody", "getValidatedQuery" ]
  }
]
  1. create unjs presets.

    This would be similar to the unjs/unkit philosophy.

    • Advantage: no impact on users even if unjs stack is increased
    • Disadvantage: not sure what is available in unjs presets. You need to check presets/unjs.ts to see what is available.

    Example

    • presets/unjs.ts.
presets: [
  {
    from: "unjs",
    imports: [ "consola", "EventHandler" ]
  }
]

My opinion

I would implement proposal 1 and move to proposal 2 if the number of unjs stacks required by users increases too much.

Additional information

  • Would you be willing to help implement this feature?

Identifier already declared error

Environment

unimport: 3.0.2,
npm: '8.1.2',
node: '16.13.2',

Reproduction

https://stackblitz.com/edit/vitejs-vite-z2qfyt

Run npm run build in the project root to reproduce the build error.

Describe the bug

In this repro stackblitz, I have a simple Vite project that uses the vue-ts template. I have included the unimport plugin that uses the Vue preset.

Outside the src folder, I have a my-module module that simulates an npm package.

This module has index.js that contains one of the auto imported function from Vue as a variable name. In the example, I used ref

const u = Object.defineProperty,
  ref = Object.getOwnPropertyNames;

export function getProperties(obj) {
  return ref.call(null, obj);
}

I consume this module in src/main.ts and when I try to build using Vite, I get the following error.

Identifier 'ref' has already been declared

If I were to change the my-module/index.js to this format

const u = Object.defineProperty;
const ref = Object.getOwnPropertyNames;

export function getProperties(obj) {
  return ref.call(null, obj);
}

And rebuild using Vite. Everything goes fine. It seems to have issue when variables are declared like const foo = 'bar', ref = 'baz'.

I can fix this issue my ignoring ref from the import. But similar issues could occur for any other identifier e.g. h

So I think this issue needs to be addressed by unimport itself.

image

Additional context

No response

Logs

Identifier 'ref' has already been declared
file: /home/projects/vitejs-vite-z2qfyt/my-module/index.js:7:0
5: // BREAKS
6: const u = Object.defineProperty,
7:   ref = Object.getOwnPropertyNames;
   ^
8: 
9: export function getProperties(obj) {
error during build:
RollupError: Identifier 'ref' has already been declared
    at error (file://file:///home/projects/vitejs-vite-z2qfyt/node_modules/rollup/dist/es/shared/node-entry.js:2130:30)
    at Module.error (file://file:///home/projects/vitejs-vite-z2qfyt/node_modules/rollup/dist/es/shared/node-entry.js:13199:16)
    at Module.tryParse (file://file:///home/projects/vitejs-vite-z2qfyt/node_modules/rollup/dist/es/shared/node-entry.js:13876:25)
    at Module.setSource (file://file:///home/projects/vitejs-vite-z2qfyt/node_modules/rollup/dist/es/shared/node-entry.js:13486:39)
    at ModuleLoader.addModuleSource (file://file:///home/projects/vitejs-vite-z2qfyt/node_modules/rollup/dist/es/shared/node-entry.js:23447:20)

Question: what is the purpose of `defineUnimportPreset`?

I was looking through the Nuxt source code and saw it uses defineUnimportPreset in some places. However, upon reading the source code here, it seems the defineUnimportPreset does nothing but return the passed in parameter. It doesn't even re-type it. What is the use of this function? Does it cause some obscure side effect that is desired, is it a "functional" way of ensuring the type of the preset is correct, or is it something else? If it is a type thing, why use that pattern over simply exporting the type information?

Get imports as object

Describe the feature

I'm trying to incorporate unimport in a serverless.js building pipeline with the goal of automating part of the bindings that are currently done manually to connect the lambdas.

However, while it works fine for not having to manually import the lambda in the config file, you still must add it to the functions object. The code looks more or less like this:

// import hello from functions/hello/index.ts // automated by unimport

const config = {
// ...
  functions: {
    hello,
    // ...
  }
}

I was wondering whether unimport imported exports could be grouped in an object, so to get something like:

const config = {
// ...
  functions: {
    ... unimport()
  }
}

Additional information

  • Would you be willing to help implement this feature?

Roadmap

Base

Integration

  • Unplugin (unimport/unplugin)

Presets

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.