Skip to content

Commit

Permalink
docs(glob-import): add documentation for import.meta.glob (QwikDev#5504)
Browse files Browse the repository at this point in the history
* docs(glob-import): add documentation for import.meta.glob

* docs(glob-imports): add Glob Import link to /cookbook/index.mdx

* docs(glob-import): refactor type any to Record<string, any>

* docs: add Record<string, any> to mdx as well
  • Loading branch information
maiieul committed Dec 1, 2023
1 parent c41ff19 commit 9784ec1
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { component$ } from '@builder.io/qwik';

export default component$(() => {
return (
<p>
Hi 👋, I'm a component defined in <em>/examples/example1.tsx</em>
</p>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { component$ } from '@builder.io/qwik';

export default component$(() => {
return (
<p>
Hey 👋, I'm a component defined in <em>/examples/example2.tsx</em>
</p>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { component$ } from '@builder.io/qwik';

export default component$(() => {
return (
<p>
Hello 👋, I'm a component defined in <em>/examples/example3.tsx</em>
</p>
);
});
38 changes: 38 additions & 0 deletions packages/docs/src/routes/demo/cookbook/glob-import/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
type Component,
component$,
useSignal,
useTask$,
} from '@builder.io/qwik';
import { isDev } from '@builder.io/qwik/build';

const metaGlobComponents: Record<string, any> = import.meta.glob(
'/src/routes/demo/cookbook/glob-import/examples/*',
{
import: 'default',
eager: isDev ? false : true,
}
);

export default component$(() => {
return (
<div>
<MetaGlobExample name="example1" />
<MetaGlobExample name="example2" />
<MetaGlobExample name="example3" />
</div>
);
});

export const MetaGlobExample = component$<{ name: string }>(({ name }) => {
const MetaGlobComponent = useSignal<Component<any>>();
const componentPath = `/src/routes/demo/cookbook/glob-import/examples/${name}.tsx`;

useTask$(async () => {
MetaGlobComponent.value = isDev
? await metaGlobComponents[componentPath]() // We need to call `await metaGlobComponents[componentPath]()` in development as it is `eager:false`
: metaGlobComponents[componentPath]; // We need to directly access the `metaGlobComponents[componentPath]` expression in preview/production as it is `eager:true`
});

return <>{MetaGlobComponent.value && <MetaGlobComponent.value />}</>;
});
96 changes: 96 additions & 0 deletions packages/docs/src/routes/docs/cookbook/glob-import/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: Cookbook | Glob Import with import.meta.glob
contributors:
- maiieul
---

import CodeSandbox from '../../../../components/code-sandbox/index.tsx';

# Glob Import & Dynamic Import

As you probably know, Qwik takes care of lazy-loading for you in order to make your app performant and scalable by default.

As a consequence of this automatic optimization, you don't need to and shouldn't use vite's [dynamic imports](https://vitejs.dev/guide/features#dynamic-import) feature as it conflicts with the [optimizer](<../../(qwik)/advanced/optimizer/index.mdx>).

But there are still some cases where you may need to import a lot of files from a directory and you may not want to type out all the file paths. For that kind of situation, you can use [`import.meta.glob`](https://vitejs.dev/guide/features#glob-import).

## import.meta.glob

The goal of using `import.meta.glob` is to allow you to create a wrapper component to which you can pass a name prop to chose which component you want to import:

```tsx
<MetaGlobComponent name="file-name" />
<MetaGlobComponent name="another-file-name" />
<MetaGlobComponent name="etc." />
```

As written in the Vite documentation, `import.meta.glob` comes with a few features that allow you to specify how to import your files.

By default you can simply use pattern matching to specify which files should be imported from which folder:

```tsx
const metaGlobComponents: any = import.meta.glob('/src/components/*');
```

But you can also pass in additional options like [`import`](https://vitejs.dev/guide/features#named-imports), [`as`](https://vitejs.dev/guide/features#glob-import-as), or `eager`:

```tsx
const metaGlobComponents: any = import.meta.glob('/src/components/*', {
import: 'default',
as: 'raw',
eager: true, // defaults to false
});
```

## How to

The problem with `import.meta.glob` in Qwik, is that it currently either works in development and doesn't in preview/production, or it works in preview/production but gets slower and slower in development as the number of imported files increases.

The reason for this behavior, is that `import.meta.glob` with `eager.false` breaks the production bundle as it creates lazy-loadable chunks that Qwik doesn't know how to handle. On the other hand, `eager:true` seemingly fixes the issue as it allows Qwik to normally bundle the files, but it also slows down the development server - especially when you import a lot of heavy components with it.

As a workaround for now, you can use the build time `isDev` boolean from `"@builder.io/qwik/build"`:

<CodeSandbox url="/demo/cookbook/glob-import/">
```tsx
import {
type Component,
component$,
useSignal,
useTask$,
} from '@builder.io/qwik';
import { isDev } from '@builder.io/qwik/build';

const metaGlobComponents: Record<string, any> = import.meta.glob(
'/src/examples/*',
{
import: 'default',
eager: isDev ? false : true,
}
);

export default component$(() => {
return (
<div>
<MetaGlobExample name="example1" />
<MetaGlobExample name="example2" />
<MetaGlobExample name="example3" />
</div>
);
});

export const MetaGlobExample = component$<{ name: string }>(({ name }) => {
const MetaGlobComponent = useSignal<Component<any>>();
const componentPath = `/src/examples/${name}.tsx`;

useTask$(async () => {
MetaGlobComponent.value = isDev
? await metaGlobComponents[componentPath]()
// We need to call `await metaGlobComponents[componentPath]()` in development as it is `eager:false`
: metaGlobComponents[componentPath];
// We need to directly access the `metaGlobComponents[componentPath]` expression in preview/production as it is `eager:true`
});

return <>{MetaGlobComponent.value && <MetaGlobComponent.value />}</>;
});
```
</CodeSandbox>
2 changes: 2 additions & 0 deletions packages/docs/src/routes/docs/cookbook/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ contributors:
- mhevery
- fabiobiondi
- n8sabes
- maiieul
---

# Cookbook
Expand All @@ -13,4 +14,5 @@ A cookbook contains a collection of useful patterns for solving common problems
Examples:
- [Modal Dialog Pop-Up](./portal/)
- [Media Controller with iOS Support](./mediaController/)
- [Glob Import with `import.meta.glob`](./glob-import/)
- [Theme Managment](./theme-management/)
3 changes: 2 additions & 1 deletion packages/docs/src/routes/docs/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@
## Cookbook

- [Overview](/docs/cookbook/index.mdx)
- [Portal](/docs/cookbook/portal/index.mdx)
- [Glob Import](/docs/cookbook/glob-import/index.mdx)
- [Media Controller](/docs/cookbook/mediaController/index.mdx)
- [Portal](/docs/cookbook/portal/index.mdx)

## Integrations

Expand Down

0 comments on commit 9784ec1

Please sign in to comment.