Import groups / namespaces
Opened this issue · 1 comments
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?
When the number is large enough, all variables are exposed globally, which will indeed cause certain pollution to eslintrc globals and types, and can easily cause conflicts.
Hope there was a way to do something similar:
const code = `
$.foo();
$.bar();
`
const { injectImports } = createUnimport({
imports: [
{ name: 'foo', from: 'my-lib', as: '$.foo' },
{ name: 'bar', from: 'my-lib', as: '$.bar' },
]
})
const { code } = await injectImports(code)
Output:
import { foo as $__foo, bar as $__bar } from 'my-lib';
const $ = { foo: $__foo, bar: $__bar };
$.foo();
$.bar();