@nuxt/docs 0.0.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.navigation.yml +2 -0
- package/1.getting-started/.navigation.yml +3 -0
- package/1.getting-started/01.introduction.md +81 -0
- package/1.getting-started/02.installation.md +109 -0
- package/1.getting-started/03.configuration.md +226 -0
- package/1.getting-started/04.views.md +163 -0
- package/1.getting-started/05.assets.md +48 -0
- package/1.getting-started/06.styling.md +565 -0
- package/1.getting-started/07.routing.md +149 -0
- package/1.getting-started/08.seo-meta.md +360 -0
- package/1.getting-started/09.transitions.md +473 -0
- package/1.getting-started/10.data-fetching.md +795 -0
- package/1.getting-started/11.state-management.md +223 -0
- package/1.getting-started/12.error-handling.md +233 -0
- package/1.getting-started/13.server.md +94 -0
- package/1.getting-started/14.layers.md +92 -0
- package/1.getting-started/15.prerendering.md +194 -0
- package/1.getting-started/16.deployment.md +130 -0
- package/1.getting-started/17.testing.md +728 -0
- package/1.getting-started/18.upgrade.md +997 -0
- package/2.guide/.navigation.yml +2 -0
- package/2.guide/0.index.md +22 -0
- package/2.guide/1.concepts/.navigation.yml +3 -0
- package/2.guide/1.concepts/1.auto-imports.md +205 -0
- package/2.guide/1.concepts/10.nuxt-lifecycle.md +141 -0
- package/2.guide/1.concepts/2.vuejs-development.md +103 -0
- package/2.guide/1.concepts/3.rendering.md +255 -0
- package/2.guide/1.concepts/4.server-engine.md +62 -0
- package/2.guide/1.concepts/5.modules.md +48 -0
- package/2.guide/1.concepts/7.esm.md +299 -0
- package/2.guide/1.concepts/8.typescript.md +97 -0
- package/2.guide/1.concepts/9.code-style.md +22 -0
- package/2.guide/2.directory-structure/.navigation.yml +3 -0
- package/2.guide/2.directory-structure/0.nuxt.md +20 -0
- package/2.guide/2.directory-structure/0.output.md +18 -0
- package/2.guide/2.directory-structure/1.assets.md +16 -0
- package/2.guide/2.directory-structure/1.components.md +608 -0
- package/2.guide/2.directory-structure/1.composables.md +121 -0
- package/2.guide/2.directory-structure/1.content.md +64 -0
- package/2.guide/2.directory-structure/1.layouts.md +180 -0
- package/2.guide/2.directory-structure/1.middleware.md +209 -0
- package/2.guide/2.directory-structure/1.modules.md +66 -0
- package/2.guide/2.directory-structure/1.node_modules.md +12 -0
- package/2.guide/2.directory-structure/1.pages.md +440 -0
- package/2.guide/2.directory-structure/1.plugins.md +299 -0
- package/2.guide/2.directory-structure/1.public.md +27 -0
- package/2.guide/2.directory-structure/1.server.md +546 -0
- package/2.guide/2.directory-structure/1.shared.md +104 -0
- package/2.guide/2.directory-structure/1.utils.md +49 -0
- package/2.guide/2.directory-structure/2.env.md +75 -0
- package/2.guide/2.directory-structure/2.gitignore.md +37 -0
- package/2.guide/2.directory-structure/2.nuxtignore.md +36 -0
- package/2.guide/2.directory-structure/2.nuxtrc.md +50 -0
- package/2.guide/2.directory-structure/3.app-config.md +177 -0
- package/2.guide/2.directory-structure/3.app.md +72 -0
- package/2.guide/2.directory-structure/3.error.md +55 -0
- package/2.guide/2.directory-structure/3.nuxt-config.md +34 -0
- package/2.guide/2.directory-structure/3.package.md +32 -0
- package/2.guide/2.directory-structure/3.tsconfig.md +24 -0
- package/2.guide/3.going-further/.navigation.yml +3 -0
- package/2.guide/3.going-further/1.experimental-features.md +689 -0
- package/2.guide/3.going-further/1.features.md +103 -0
- package/2.guide/3.going-further/1.internals.md +81 -0
- package/2.guide/3.going-further/10.runtime-config.md +174 -0
- package/2.guide/3.going-further/11.nightly-release-channel.md +68 -0
- package/2.guide/3.going-further/2.hooks.md +98 -0
- package/2.guide/3.going-further/3.modules.md +811 -0
- package/2.guide/3.going-further/4.kit.md +51 -0
- package/2.guide/3.going-further/6.nuxt-app.md +64 -0
- package/2.guide/3.going-further/7.layers.md +227 -0
- package/2.guide/3.going-further/9.debugging.md +115 -0
- package/2.guide/3.going-further/index.md +4 -0
- package/2.guide/4.recipes/.navigation.yml +3 -0
- package/2.guide/4.recipes/1.custom-routing.md +181 -0
- package/2.guide/4.recipes/2.vite-plugin.md +65 -0
- package/2.guide/4.recipes/3.custom-usefetch.md +125 -0
- package/2.guide/4.recipes/4.sessions-and-authentication.md +203 -0
- package/3.api/.navigation.yml +3 -0
- package/3.api/1.components/.navigation.yml +3 -0
- package/3.api/1.components/1.client-only.md +76 -0
- package/3.api/1.components/1.dev-only.md +51 -0
- package/3.api/1.components/1.nuxt-client-fallback.md +80 -0
- package/3.api/1.components/10.nuxt-picture.md +27 -0
- package/3.api/1.components/11.teleports.md +40 -0
- package/3.api/1.components/12.nuxt-route-announcer.md +56 -0
- package/3.api/1.components/13.nuxt-time.md +173 -0
- package/3.api/1.components/2.nuxt-page.md +154 -0
- package/3.api/1.components/3.nuxt-layout.md +156 -0
- package/3.api/1.components/4.nuxt-link.md +322 -0
- package/3.api/1.components/5.nuxt-loading-indicator.md +50 -0
- package/3.api/1.components/6.nuxt-error-boundary.md +65 -0
- package/3.api/1.components/7.nuxt-welcome.md +25 -0
- package/3.api/1.components/8.nuxt-island.md +70 -0
- package/3.api/1.components/9.nuxt-img.md +43 -0
- package/3.api/2.composables/.navigation.yml +3 -0
- package/3.api/2.composables/on-prehydrate.md +60 -0
- package/3.api/2.composables/use-app-config.md +19 -0
- package/3.api/2.composables/use-async-data.md +212 -0
- package/3.api/2.composables/use-cookie.md +233 -0
- package/3.api/2.composables/use-error.md +32 -0
- package/3.api/2.composables/use-fetch.md +217 -0
- package/3.api/2.composables/use-head-safe.md +55 -0
- package/3.api/2.composables/use-head.md +69 -0
- package/3.api/2.composables/use-hydration.md +68 -0
- package/3.api/2.composables/use-lazy-async-data.md +47 -0
- package/3.api/2.composables/use-lazy-fetch.md +55 -0
- package/3.api/2.composables/use-loading-indicator.md +77 -0
- package/3.api/2.composables/use-nuxt-app.md +294 -0
- package/3.api/2.composables/use-nuxt-data.md +112 -0
- package/3.api/2.composables/use-preview-mode.md +118 -0
- package/3.api/2.composables/use-request-event.md +23 -0
- package/3.api/2.composables/use-request-fetch.md +52 -0
- package/3.api/2.composables/use-request-header.md +34 -0
- package/3.api/2.composables/use-request-headers.md +37 -0
- package/3.api/2.composables/use-request-url.md +41 -0
- package/3.api/2.composables/use-response-header.md +48 -0
- package/3.api/2.composables/use-route-announcer.md +60 -0
- package/3.api/2.composables/use-route.md +52 -0
- package/3.api/2.composables/use-router.md +92 -0
- package/3.api/2.composables/use-runtime-config.md +142 -0
- package/3.api/2.composables/use-runtime-hook.md +43 -0
- package/3.api/2.composables/use-seo-meta.md +80 -0
- package/3.api/2.composables/use-server-seo-meta.md +27 -0
- package/3.api/2.composables/use-state.md +48 -0
- package/3.api/3.utils/$fetch.md +98 -0
- package/3.api/3.utils/.navigation.yml +3 -0
- package/3.api/3.utils/abort-navigation.md +73 -0
- package/3.api/3.utils/add-route-middleware.md +88 -0
- package/3.api/3.utils/call-once.md +92 -0
- package/3.api/3.utils/clear-error.md +29 -0
- package/3.api/3.utils/clear-nuxt-data.md +23 -0
- package/3.api/3.utils/clear-nuxt-state.md +23 -0
- package/3.api/3.utils/create-error.md +55 -0
- package/3.api/3.utils/define-nuxt-component.md +53 -0
- package/3.api/3.utils/define-nuxt-route-middleware.md +67 -0
- package/3.api/3.utils/define-page-meta.md +234 -0
- package/3.api/3.utils/define-route-rules.md +52 -0
- package/3.api/3.utils/navigate-to.md +230 -0
- package/3.api/3.utils/on-before-route-leave.md +11 -0
- package/3.api/3.utils/on-before-route-update.md +11 -0
- package/3.api/3.utils/on-nuxt-ready.md +25 -0
- package/3.api/3.utils/prefetch-components.md +28 -0
- package/3.api/3.utils/preload-components.md +23 -0
- package/3.api/3.utils/preload-route-components.md +41 -0
- package/3.api/3.utils/prerender-routes.md +46 -0
- package/3.api/3.utils/refresh-cookie.md +46 -0
- package/3.api/3.utils/refresh-nuxt-data.md +91 -0
- package/3.api/3.utils/reload-nuxt-app.md +74 -0
- package/3.api/3.utils/set-page-layout.md +24 -0
- package/3.api/3.utils/set-response-status.md +36 -0
- package/3.api/3.utils/show-error.md +31 -0
- package/3.api/3.utils/update-app-config.md +27 -0
- package/3.api/4.commands/.navigation.yml +3 -0
- package/3.api/4.commands/add.md +112 -0
- package/3.api/4.commands/analyze.md +41 -0
- package/3.api/4.commands/build-module.md +42 -0
- package/3.api/4.commands/build.md +46 -0
- package/3.api/4.commands/cleanup.md +38 -0
- package/3.api/4.commands/dev.md +59 -0
- package/3.api/4.commands/devtools.md +38 -0
- package/3.api/4.commands/generate.md +41 -0
- package/3.api/4.commands/info.md +33 -0
- package/3.api/4.commands/init.md +46 -0
- package/3.api/4.commands/module.md +84 -0
- package/3.api/4.commands/prepare.md +36 -0
- package/3.api/4.commands/preview.md +43 -0
- package/3.api/4.commands/typecheck.md +42 -0
- package/3.api/4.commands/upgrade.md +37 -0
- package/3.api/5.kit/.navigation.yml +3 -0
- package/3.api/5.kit/1.modules.md +172 -0
- package/3.api/5.kit/10.runtime-config.md +27 -0
- package/3.api/5.kit/10.templates.md +283 -0
- package/3.api/5.kit/11.nitro.md +409 -0
- package/3.api/5.kit/12.resolving.md +268 -0
- package/3.api/5.kit/13.logging.md +65 -0
- package/3.api/5.kit/14.builder.md +491 -0
- package/3.api/5.kit/15.examples.md +41 -0
- package/3.api/5.kit/2.programmatic.md +125 -0
- package/3.api/5.kit/3.compatibility.md +230 -0
- package/3.api/5.kit/4.autoimports.md +144 -0
- package/3.api/5.kit/5.components.md +127 -0
- package/3.api/5.kit/6.context.md +130 -0
- package/3.api/5.kit/7.pages.md +295 -0
- package/3.api/5.kit/8.layout.md +80 -0
- package/3.api/5.kit/9.plugins.md +263 -0
- package/3.api/6.advanced/.navigation.yml +1 -0
- package/3.api/6.advanced/1.hooks.md +105 -0
- package/3.api/6.advanced/2.import-meta.md +60 -0
- package/3.api/6.nuxt-config.md +12 -0
- package/3.api/index.md +31 -0
- package/5.community/.navigation.yml +3 -0
- package/5.community/2.getting-help.md +48 -0
- package/5.community/3.reporting-bugs.md +50 -0
- package/5.community/4.contribution.md +205 -0
- package/5.community/5.framework-contribution.md +142 -0
- package/5.community/6.roadmap.md +79 -0
- package/5.community/7.changelog.md +92 -0
- package/6.bridge/.navigation.yml +3 -0
- package/6.bridge/1.overview.md +137 -0
- package/6.bridge/10.configuration.md +96 -0
- package/6.bridge/2.typescript.md +46 -0
- package/6.bridge/3.bridge-composition-api.md +132 -0
- package/6.bridge/4.plugins-and-middleware.md +65 -0
- package/6.bridge/5.nuxt3-compatible-api.md +204 -0
- package/6.bridge/6.meta.md +117 -0
- package/6.bridge/7.runtime-config.md +38 -0
- package/6.bridge/8.nitro.md +102 -0
- package/6.bridge/9.vite.md +37 -0
- package/7.migration/.navigation.yml +3 -0
- package/7.migration/1.overview.md +24 -0
- package/7.migration/10.bundling.md +28 -0
- package/7.migration/11.server.md +17 -0
- package/7.migration/2.configuration.md +240 -0
- package/7.migration/20.module-authors.md +94 -0
- package/7.migration/3.auto-imports.md +18 -0
- package/7.migration/4.meta.md +127 -0
- package/7.migration/5.plugins-and-middleware.md +80 -0
- package/7.migration/6.pages-and-layouts.md +233 -0
- package/7.migration/7.component-options.md +156 -0
- package/7.migration/8.runtime-config.md +58 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/package.json +16 -4
- package/dist/.gitkeep +0 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Rendering Modes'
|
|
3
|
+
description: 'Learn about the different rendering modes available in Nuxt.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Nuxt supports different rendering modes, [universal rendering](#universal-rendering), [client-side rendering](#client-side-rendering) but also offers [hybrid-rendering](#hybrid-rendering) and the possibility to render your application on [CDN Edge Servers](#edge-side-rendering).
|
|
7
|
+
|
|
8
|
+
Both the browser and server can interpret JavaScript code to turn Vue.js components into HTML elements. This step is called **rendering**. Nuxt supports both **universal** and **client-side** rendering. The two approaches have benefits and downsides that we will cover.
|
|
9
|
+
|
|
10
|
+
By default, Nuxt uses **universal rendering** to provide better user experience, performance and to optimize search engine indexing, but you can switch rendering modes in [one line of configuration](/docs/api/nuxt-config#ssr).
|
|
11
|
+
|
|
12
|
+
## Universal Rendering
|
|
13
|
+
|
|
14
|
+
This step is similar to traditional **server-side rendering** performed by PHP or Ruby applications. When the browser requests a URL with universal rendering enabled, Nuxt runs the JavaScript (Vue.js) code in a server environment and returns a fully rendered HTML page to the browser. Nuxt may also return a fully rendered HTML page from a cache if the page was generated in advance. Users immediately get the entirety of the initial content of the application, contrary to client-side rendering.
|
|
15
|
+
|
|
16
|
+
Once the HTML document has been downloaded, the browser interprets this and Vue.js takes control of the document. The same JavaScript code that once ran on the server runs on the client (browser) **again** in the background now enabling interactivity (hence **Universal rendering**) by binding its listeners to the HTML. This is called **Hydration**. When hydration is complete, the page can enjoy benefits such as dynamic interfaces and page transitions.
|
|
17
|
+
|
|
18
|
+
Universal rendering allows a Nuxt application to provide quick page load times while preserving the benefits of client-side rendering. Furthermore, as the content is already present in the HTML document, crawlers can index it without overhead.
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
**What's server-rendered and what's client-rendered?**
|
|
23
|
+
|
|
24
|
+
It is normal to ask which parts of a Vue file runs on the server and/or the client in universal rendering mode.
|
|
25
|
+
|
|
26
|
+
```vue [app.vue]
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
const counter = ref(0); // executes in server and client environments
|
|
29
|
+
|
|
30
|
+
const handleClick = () => {
|
|
31
|
+
counter.value++; // executes only in a client environment
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div>
|
|
37
|
+
<p>Count: {{ counter }}</p>
|
|
38
|
+
<button @click="handleClick">Increment</button>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
On the initial request, the `counter` ref is initialized in the server since it is rendered inside the `<p>` tag. The contents of `handleClick` is never executed here. During hydration in the browser, the `counter` ref is re-initialized. The `handleClick` finally binds itself to the button; Therefore it is reasonable to deduce that the body of `handleClick` will always run in a browser environment.
|
|
44
|
+
|
|
45
|
+
[Middlewares](/docs/guide/directory-structure/middleware) and [pages](/docs/guide/directory-structure/pages) run in the server and on the client during hydration. [Plugins](/docs/guide/directory-structure/plugins) can be rendered on the server or client or both. [Components](/docs/guide/directory-structure/components) can be forced to run on the client only as well. [Composables](/docs/guide/directory-structure/composables) and [utilities](/docs/guide/directory-structure/utils) are rendered based on the context of their usage.
|
|
46
|
+
|
|
47
|
+
**Benefits of server-side rendering:**
|
|
48
|
+
- **Performance**: Users can get immediate access to the page's content because browsers can display static content much faster than JavaScript-generated content. At the same time, Nuxt preserves the interactivity of a web application during the hydration process.
|
|
49
|
+
- **Search Engine Optimization**: Universal rendering delivers the entire HTML content of the page to the browser as a classic server application. Web crawlers can directly index the page's content, which makes Universal rendering a great choice for any content that you want to index quickly.
|
|
50
|
+
|
|
51
|
+
**Downsides of server-side rendering:**
|
|
52
|
+
- **Development constraints:** Server and browser environments don't provide the same APIs, and it can be tricky to write code that can run on both sides seamlessly. Fortunately, Nuxt provides guidelines and specific variables to help you determine where a piece of code is executed.
|
|
53
|
+
- **Cost:** A server needs to be running in order to render pages on the fly. This adds a monthly cost like any traditional server. However, the server calls are highly reduced thanks to universal rendering with the browser taking over on client-side navigation. A cost reduction is possible by leveraging [edge-side-rendering](#edge-side-rendering).
|
|
54
|
+
|
|
55
|
+
Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: **blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.**
|
|
56
|
+
|
|
57
|
+
::tip
|
|
58
|
+
For more examples about writing Vue code without hydration mismatch, see [the Vue docs](https://vuejs.org/guide/scaling-up/ssr.html#hydration-mismatch).
|
|
59
|
+
::
|
|
60
|
+
|
|
61
|
+
::important
|
|
62
|
+
When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects.
|
|
63
|
+
::
|
|
64
|
+
|
|
65
|
+
## Client-Side Rendering
|
|
66
|
+
|
|
67
|
+
Out of the box, a traditional Vue.js application is rendered in the browser (or **client**). Then, Vue.js generates HTML elements after the browser downloads and parses all the JavaScript code containing the instructions to create the current interface.
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
**Benefits of client-side rendering:**
|
|
72
|
+
- **Development speed**: When working entirely on the client-side, we don't have to worry about the server compatibility of the code, for example, by using browser-only APIs like the `window` object.
|
|
73
|
+
- **Cheaper:** Running a server adds a cost of infrastructure as you would need to run on a platform that supports JavaScript. We can host Client-only applications on any static server with HTML, CSS, and JavaScript files.
|
|
74
|
+
- **Offline:** Because code entirely runs in the browser, it can nicely keep working while the internet is unavailable.
|
|
75
|
+
|
|
76
|
+
**Downsides of client-side rendering:**
|
|
77
|
+
- **Performance**: The user has to wait for the browser to download, parse and run JavaScript files. Depending on the network for the download part and the user's device for the parsing and execution, this can take some time and impact the user's experience.
|
|
78
|
+
- **Search Engine Optimization**: Indexing and updating the content delivered via client-side rendering takes more time than with a server-rendered HTML document. This is related to the performance drawback we discussed, as search engine crawlers won't wait for the interface to be fully rendered on their first try to index the page. Your content will take more time to show and update in search results pages with pure client-side rendering.
|
|
79
|
+
|
|
80
|
+
Client-side rendering is a good choice for heavily interactive **web applications** that don't need indexing or whose users visit frequently. It can leverage browser caching to skip the download phase on subsequent visits, such as **SaaS, back-office applications, or online games**.
|
|
81
|
+
|
|
82
|
+
You can enable client-side only rendering with Nuxt in your `nuxt.config.ts`:
|
|
83
|
+
|
|
84
|
+
```ts [nuxt.config.ts]
|
|
85
|
+
export default defineNuxtConfig({
|
|
86
|
+
ssr: false
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
::note
|
|
91
|
+
If you do use `ssr: false`, you should also place an HTML file in `~/app/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated.
|
|
92
|
+
:read-more{title="SPA Loading Template" to="/docs/api/configuration/nuxt-config#spaloadingtemplate"}
|
|
93
|
+
::
|
|
94
|
+
|
|
95
|
+
:video-accordion{title="Watch a video from Alexander Lichter about Building a plain SPA with Nuxt" videoId="7Lr0QTP1Ro8"}
|
|
96
|
+
|
|
97
|
+
### Deploying a Static Client-Rendered App
|
|
98
|
+
|
|
99
|
+
If you deploy your app to [static hosting](/docs/getting-started/deployment#static-hosting) with the `nuxi generate` or `nuxi build --prerender` commands, then by default, Nuxt will render every page as a separate static HTML file.
|
|
100
|
+
|
|
101
|
+
::warning
|
|
102
|
+
If you prerender your app with the `nuxi generate` or `nuxi build --prerender` commands, then you will not be able to use any server endpoints as no server will be included in your output folder. If you need server functionality, use `nuxi build` instead.
|
|
103
|
+
::
|
|
104
|
+
|
|
105
|
+
If you are using purely client-side rendering, then this might be unnecessary. You might only need a single `index.html` file, plus `200.html` and `404.html` fallbacks, which you can tell your static web host to serve up for all requests.
|
|
106
|
+
|
|
107
|
+
In order to achieve this we can change how the routes are prerendered. Just add this to [your hooks](/docs/api/advanced/hooks#nuxt-hooks-build-time) in your `nuxt.config.ts`:
|
|
108
|
+
|
|
109
|
+
```ts twoslash [nuxt.config.ts]
|
|
110
|
+
export default defineNuxtConfig({
|
|
111
|
+
hooks: {
|
|
112
|
+
'prerender:routes' ({ routes }) {
|
|
113
|
+
routes.clear() // Do not generate any routes (except the defaults)
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This will produce three files:
|
|
120
|
+
|
|
121
|
+
- `index.html`
|
|
122
|
+
- `200.html`
|
|
123
|
+
- `404.html`
|
|
124
|
+
|
|
125
|
+
The `200.html` and `404.html` might be useful for the hosting provider you are using.
|
|
126
|
+
|
|
127
|
+
#### Skipping Client Fallback Generation
|
|
128
|
+
|
|
129
|
+
When prerendering a client-rendered app, Nuxt will generate `index.html`, `200.html` and `404.html` files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the `'prerender:generate'` hook from [Nitro](/docs/getting-started/prerendering#prerendergenerate-nitro-hook).
|
|
130
|
+
|
|
131
|
+
```ts twoslash [nuxt.config.ts]
|
|
132
|
+
export default defineNuxtConfig({
|
|
133
|
+
ssr: false,
|
|
134
|
+
nitro: {
|
|
135
|
+
hooks: {
|
|
136
|
+
'prerender:generate'(route) {
|
|
137
|
+
const routesToSkip = ['/index.html', '/200.html', '/404.html']
|
|
138
|
+
if (routesToSkip.includes(route.route)) {
|
|
139
|
+
route.skip = true
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Hybrid Rendering
|
|
148
|
+
|
|
149
|
+
Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL.
|
|
150
|
+
|
|
151
|
+
Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application.
|
|
152
|
+
|
|
153
|
+
Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route!
|
|
154
|
+
|
|
155
|
+
Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.unjs.io/guide/cache).
|
|
156
|
+
|
|
157
|
+
```ts twoslash [nuxt.config.ts]
|
|
158
|
+
export default defineNuxtConfig({
|
|
159
|
+
routeRules: {
|
|
160
|
+
// Homepage pre-rendered at build time
|
|
161
|
+
'/': { prerender: true },
|
|
162
|
+
// Products page generated on demand, revalidates in background, cached until API response changes
|
|
163
|
+
'/products': { swr: true },
|
|
164
|
+
// Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds)
|
|
165
|
+
'/products/**': { swr: 3600 },
|
|
166
|
+
// Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds)
|
|
167
|
+
'/blog': { isr: 3600 },
|
|
168
|
+
// Blog post page generated on demand once until next deployment, cached on CDN
|
|
169
|
+
'/blog/**': { isr: true },
|
|
170
|
+
// Admin dashboard renders only on client-side
|
|
171
|
+
'/admin/**': { ssr: false },
|
|
172
|
+
// Add cors headers on API routes
|
|
173
|
+
'/api/**': { cors: true },
|
|
174
|
+
// Redirects legacy urls
|
|
175
|
+
'/old-page': { redirect: '/new-page' }
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Route Rules
|
|
181
|
+
|
|
182
|
+
The different properties you can use are the following:
|
|
183
|
+
- `redirect: string`{lang=ts} - Define server-side redirects.
|
|
184
|
+
- `ssr: boolean`{lang=ts} - Disables server-side rendering of the HTML for sections of your app and make them render only in the browser with `ssr: false`
|
|
185
|
+
- `cors: boolean`{lang=ts} - Automatically adds cors headers with `cors: true` - you can customize the output by overriding with `headers`
|
|
186
|
+
- `headers: object`{lang=ts} - Add specific headers to sections of your site - for example, your assets
|
|
187
|
+
- `swr: number | boolean`{lang=ts} - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge.
|
|
188
|
+
- `isr: number | boolean`{lang=ts} - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN.
|
|
189
|
+
- `prerender: boolean`{lang=ts} - Prerenders routes at build time and includes them in your build as static assets
|
|
190
|
+
- `noScripts: boolean`{lang=ts} - Disables rendering of Nuxt scripts and JS resource hints for sections of your site.
|
|
191
|
+
- `appMiddleware: string | string[] | Record<string, boolean>`{lang=ts} - Allows you to define middleware that should or should not run for page paths within the Vue app part of your application (that is, not your Nitro routes)
|
|
192
|
+
|
|
193
|
+
Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported).
|
|
194
|
+
|
|
195
|
+
::important
|
|
196
|
+
Note that Hybrid Rendering is not available when using [`nuxt generate`](/docs/api/commands/generate).
|
|
197
|
+
::
|
|
198
|
+
|
|
199
|
+
**Examples:**
|
|
200
|
+
|
|
201
|
+
::card-group
|
|
202
|
+
::card
|
|
203
|
+
---
|
|
204
|
+
icon: i-simple-icons-github
|
|
205
|
+
title: Nuxt Vercel ISR
|
|
206
|
+
to: https://github.com/danielroe/nuxt-vercel-isr
|
|
207
|
+
target: _blank
|
|
208
|
+
ui.icon.base: text-black dark:text-white
|
|
209
|
+
---
|
|
210
|
+
Example of a Nuxt application with hybrid rendering deployed on Vercel.
|
|
211
|
+
::
|
|
212
|
+
::
|
|
213
|
+
|
|
214
|
+
## Edge-Side Rendering
|
|
215
|
+
|
|
216
|
+
Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience.
|
|
217
|
+
|
|
218
|
+
With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode.
|
|
219
|
+
|
|
220
|
+
When a request for a page is made, instead of going all the way to the original server, it's intercepted by the nearest edge server. This server generates the HTML for the page and sends it back to the user. This process minimizes the physical distance the data has to travel, **reducing latency and loading the page faster**.
|
|
221
|
+
|
|
222
|
+
Edge-side rendering is possible thanks to [Nitro](https://nitro.unjs.io), the [server engine](/docs/guide/concepts/server-engine) that powers Nuxt. It offers cross-platform support for Node.js, Deno, Cloudflare Workers, and more.
|
|
223
|
+
|
|
224
|
+
The current platforms where you can leverage ESR are:
|
|
225
|
+
- [Cloudflare Pages](https://pages.cloudflare.com) with zero configuration using the git integration and the `nuxt build` command
|
|
226
|
+
- [Vercel Edge Functions](https://vercel.com/features/edge-functions) using the `nuxt build` command and `NITRO_PRESET=vercel-edge` environment variable
|
|
227
|
+
- [Netlify Edge Functions](https://www.netlify.com/products/#netlify-edge-functions) using the `nuxt build` command and `NITRO_PRESET=netlify-edge` environment variable
|
|
228
|
+
|
|
229
|
+
Note that **Hybrid Rendering** can be used when using Edge-Side Rendering with route rules.
|
|
230
|
+
|
|
231
|
+
You can explore open source examples deployed on some of the platform mentioned above:
|
|
232
|
+
::card-group
|
|
233
|
+
::card
|
|
234
|
+
---
|
|
235
|
+
icon: i-simple-icons-github
|
|
236
|
+
title: Nuxt Todos Edge
|
|
237
|
+
to: https://github.com/atinux/nuxt-todos-edge
|
|
238
|
+
target: _blank
|
|
239
|
+
ui.icon.base: text-black dark:text-white
|
|
240
|
+
---
|
|
241
|
+
A todos application with user authentication, SSR and SQLite.
|
|
242
|
+
::
|
|
243
|
+
::card
|
|
244
|
+
---
|
|
245
|
+
icon: i-simple-icons-github
|
|
246
|
+
title: Atinotes
|
|
247
|
+
to: https://github.com/atinux/atinotes
|
|
248
|
+
target: _blank
|
|
249
|
+
ui.icon.base: text-black dark:text-white
|
|
250
|
+
---
|
|
251
|
+
An editable website with universal rendering based on Cloudflare KV.
|
|
252
|
+
::
|
|
253
|
+
::
|
|
254
|
+
|
|
255
|
+
<!-- TODO: link to templates with ESR category for examples -->
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Server Engine
|
|
3
|
+
description: 'Nuxt is powered by a new server engine: Nitro.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
While building Nuxt, we created a new server engine: [Nitro](https://nitro.unjs.io).
|
|
7
|
+
|
|
8
|
+
It is shipped with many features:
|
|
9
|
+
|
|
10
|
+
- Cross-platform support for Node.js, browsers, service workers and more.
|
|
11
|
+
- Serverless support out-of-the-box.
|
|
12
|
+
- API routes support.
|
|
13
|
+
- Automatic code-splitting and async-loaded chunks.
|
|
14
|
+
- Hybrid mode for static + serverless sites.
|
|
15
|
+
- Development server with hot module reloading.
|
|
16
|
+
|
|
17
|
+
## API Layer
|
|
18
|
+
|
|
19
|
+
Server [API endpoints](/docs/guide/directory-structure/server#api-routes) and [Middleware](/docs/guide/directory-structure/server#server-middleware) are added by Nitro that internally uses [h3](https://github.com/unjs/h3).
|
|
20
|
+
|
|
21
|
+
Key features include:
|
|
22
|
+
|
|
23
|
+
- Handlers can directly return objects/arrays for an automatically-handled JSON response
|
|
24
|
+
- Handlers can return promises, which will be awaited (`res.end()` and `next()` are also supported)
|
|
25
|
+
- Helper functions for body parsing, cookie handling, redirects, headers and more
|
|
26
|
+
|
|
27
|
+
Check out [the h3 docs](https://github.com/unjs/h3) for more information.
|
|
28
|
+
|
|
29
|
+
::read-more{to="/docs/guide/directory-structure/server#server-routes"}
|
|
30
|
+
Learn more about the API layer in the `server/` directory.
|
|
31
|
+
::
|
|
32
|
+
|
|
33
|
+
## Direct API Calls
|
|
34
|
+
|
|
35
|
+
Nitro allows 'direct' calling of routes via the globally-available [`$fetch`](/docs/api/utils/dollarfetch) helper. This will make an API call to the server if run on the browser, but will directly call the relevant function if run on the server, **saving an additional API call**.
|
|
36
|
+
|
|
37
|
+
[`$fetch`](/docs/api/utils/dollarfetch) API is using [ofetch](https://github.com/unjs/ofetch), with key features including:
|
|
38
|
+
|
|
39
|
+
- Automatic parsing of JSON responses (with access to raw response if needed)
|
|
40
|
+
- Request body and params are automatically handled, with correct `Content-Type` headers
|
|
41
|
+
|
|
42
|
+
For more information on `$fetch` features, check out [ofetch](https://github.com/unjs/ofetch).
|
|
43
|
+
|
|
44
|
+
## Typed API Routes
|
|
45
|
+
|
|
46
|
+
When using API routes (or middleware), Nitro will generate typings for these routes as long as you are returning a value instead of using `res.end()` to send a response.
|
|
47
|
+
|
|
48
|
+
You can access these types when using [`$fetch()`](/docs/api/utils/dollarfetch) or [`useFetch()`](/docs/api/composables/use-fetch).
|
|
49
|
+
|
|
50
|
+
## Standalone Server
|
|
51
|
+
|
|
52
|
+
Nitro produces a standalone server dist that is independent of `node_modules`.
|
|
53
|
+
|
|
54
|
+
The server in Nuxt 2 is not standalone and requires part of Nuxt core to be involved by running `nuxt start` (with the [`nuxt-start`](https://www.npmjs.com/package/nuxt-start) or [`nuxt`](https://www.npmjs.com/package/nuxt) distributions) or custom programmatic usage, which is fragile and prone to breakage and not suitable for serverless and service worker environments.
|
|
55
|
+
|
|
56
|
+
Nuxt generates this dist when running `nuxt build` into a [`.output`](/docs/guide/directory-structure/output) directory.
|
|
57
|
+
|
|
58
|
+
The output contains runtime code to run your Nuxt server in any environment (including experimental browser service workers!) and serve your static files, making it a true hybrid framework for the JAMstack. In addition, Nuxt implements a native storage layer, supporting multi-source drivers and local assets.
|
|
59
|
+
|
|
60
|
+
::read-more{icon="i-simple-icons-github" to="https://github.com/nitrojs/nitro" target="_blank"}
|
|
61
|
+
Read more about Nitro engine on GitHub.
|
|
62
|
+
::
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Modules'
|
|
3
|
+
description: "Nuxt provides a module system to extend the framework core and simplify integrations."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Exploring Nuxt Modules
|
|
7
|
+
|
|
8
|
+
When developing production-grade applications with Nuxt you might find that the framework's core functionality is not enough. Nuxt can be extended with configuration options and plugins, but maintaining these customizations across multiple projects can be tedious, repetitive and time-consuming. On the other hand, supporting every project's needs out of the box would make Nuxt very complex and hard to use.
|
|
9
|
+
|
|
10
|
+
This is one of the reasons why Nuxt provides a module system that makes it possible to extend the core. Nuxt modules are async functions that sequentially run when starting Nuxt in development mode using [`nuxi dev`](/docs/api/commands/dev) or building a project for production with [`nuxi build`](/docs/api/commands/build). They can override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks.
|
|
11
|
+
|
|
12
|
+
Best of all, Nuxt modules can be distributed in npm packages. This makes it possible for them to be reused across projects and shared with the community, helping create an ecosystem of high-quality add-ons.
|
|
13
|
+
|
|
14
|
+
::read-more{to="/modules"}
|
|
15
|
+
Explore Nuxt Modules
|
|
16
|
+
::
|
|
17
|
+
|
|
18
|
+
## Add Nuxt Modules
|
|
19
|
+
|
|
20
|
+
Once you have installed the modules you can add them to your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file under the `modules` property. Module developers usually provide additional steps and details for usage.
|
|
21
|
+
|
|
22
|
+
```ts twoslash [nuxt.config.ts]
|
|
23
|
+
export default defineNuxtConfig({
|
|
24
|
+
modules: [
|
|
25
|
+
// Using package name (recommended usage)
|
|
26
|
+
'@nuxtjs/example',
|
|
27
|
+
|
|
28
|
+
// Load a local module
|
|
29
|
+
'./modules/example',
|
|
30
|
+
|
|
31
|
+
// Add module with inline-options
|
|
32
|
+
['./modules/example', { token: '123' }],
|
|
33
|
+
|
|
34
|
+
// Inline module definition
|
|
35
|
+
async (inlineOptions, nuxt) => { }
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
::warning
|
|
41
|
+
Nuxt modules are now build-time-only, and the `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`.
|
|
42
|
+
::
|
|
43
|
+
|
|
44
|
+
## Create a Nuxt Module
|
|
45
|
+
|
|
46
|
+
Everyone has the opportunity to develop modules and we cannot wait to see what you will build.
|
|
47
|
+
|
|
48
|
+
:read-more{to="/docs/guide/going-further/modules" title="Module Author Guide"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'ES Modules'
|
|
3
|
+
description: "Nuxt uses native ES modules."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This guide helps explain what ES Modules are and how to make a Nuxt app (or upstream library) compatible with ESM.
|
|
7
|
+
|
|
8
|
+
## Background
|
|
9
|
+
|
|
10
|
+
### CommonJS Modules
|
|
11
|
+
|
|
12
|
+
CommonJS (CJS) is a format introduced by Node.js that allows sharing functionality between isolated JavaScript modules ([read more](https://nodejs.org/api/modules.html)).
|
|
13
|
+
You might be already familiar with this syntax:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
const a = require('./a')
|
|
17
|
+
|
|
18
|
+
module.exports.a = a
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Bundlers like webpack and Rollup support this syntax and allow you to use modules written in CommonJS in the browser.
|
|
22
|
+
|
|
23
|
+
### ESM Syntax
|
|
24
|
+
|
|
25
|
+
Most of the time, when people talk about ESM vs. CJS, they are talking about a different syntax for writing [modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules).
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import a from './a'
|
|
29
|
+
|
|
30
|
+
export { a }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Before ECMAScript Modules (ESM) became a standard (it took more than 10 years!), tooling like
|
|
34
|
+
[webpack](https://webpack.js.org/guides/ecma-script-modules) and even languages like TypeScript started supporting so-called **ESM syntax**.
|
|
35
|
+
However, there are some key differences with actual spec; here's [a helpful explainer](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive).
|
|
36
|
+
|
|
37
|
+
### What is 'Native' ESM?
|
|
38
|
+
|
|
39
|
+
You may have been writing your app using ESM syntax for a long time. After all, it's natively supported by the browser, and in Nuxt 2 we compiled all the code you wrote to the appropriate format (CJS for server, ESM for browser).
|
|
40
|
+
|
|
41
|
+
When adding modules to your package, things were a little different. A sample library might expose both CJS and ESM versions, and let us pick which one we wanted:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"name": "sample-library",
|
|
46
|
+
"main": "dist/sample-library.cjs.js",
|
|
47
|
+
"module": "dist/sample-library.esm.js"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
So in Nuxt 2, the bundler (webpack) would pull in the CJS file ('main') for the server build and use the ESM file ('module') for the client build.
|
|
52
|
+
|
|
53
|
+
However, in recent Node.js LTS releases, it is now possible to [use native ESM module](https://nodejs.org/api/esm.html) within Node.js. That means that Node.js itself can process JavaScript using ESM syntax, although it doesn't do it by default. The two most common ways to enable ESM syntax are:
|
|
54
|
+
|
|
55
|
+
- set `"type": "module"` within your `package.json` and keep using `.js` extension
|
|
56
|
+
- use the `.mjs` file extensions (recommended)
|
|
57
|
+
|
|
58
|
+
This is what we do for Nuxt Nitro; we output a `.output/server/index.mjs` file. That tells Node.js to treat this file as a native ES module.
|
|
59
|
+
|
|
60
|
+
### What Are Valid Imports in a Node.js Context?
|
|
61
|
+
|
|
62
|
+
When you `import` a module rather than `require` it, Node.js resolves it differently. For example, when you import `sample-library`, Node.js will look not for the `main` but for the `exports` or `module` entry in that library's `package.json`.
|
|
63
|
+
|
|
64
|
+
This is also true of dynamic imports, like `const b = await import('sample-library')`.
|
|
65
|
+
|
|
66
|
+
Node supports the following kinds of imports (see [docs](https://nodejs.org/api/packages.html#determining-module-system)):
|
|
67
|
+
|
|
68
|
+
1. files ending in `.mjs` - these are expected to use ESM syntax
|
|
69
|
+
1. files ending in `.cjs` - these are expected to use CJS syntax
|
|
70
|
+
1. files ending in `.js` - these are expected to use CJS syntax unless their `package.json` has `"type": "module"`
|
|
71
|
+
|
|
72
|
+
### What Kinds of Problems Can There Be?
|
|
73
|
+
|
|
74
|
+
For a long time module authors have been producing ESM-syntax builds but using conventions like `.esm.js` or `.es.js`, which they have added to the `module` field in their `package.json`. This hasn't been a problem until now because they have only been used by bundlers like webpack, which don't especially care about the file extension.
|
|
75
|
+
|
|
76
|
+
However, if you try to import a package with an `.esm.js` file in a Node.js ESM context, it won't work, and you'll get an error like:
|
|
77
|
+
|
|
78
|
+
```bash [Terminal]
|
|
79
|
+
(node:22145) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
|
|
80
|
+
/path/to/index.js:1
|
|
81
|
+
|
|
82
|
+
export default {}
|
|
83
|
+
^^^^^^
|
|
84
|
+
|
|
85
|
+
SyntaxError: Unexpected token 'export'
|
|
86
|
+
at wrapSafe (internal/modules/cjs/loader.js:1001:16)
|
|
87
|
+
at Module._compile (internal/modules/cjs/loader.js:1049:27)
|
|
88
|
+
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
|
|
89
|
+
....
|
|
90
|
+
at async Object.loadESM (internal/process/esm_loader.js:68:5)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
You might also get this error if you have a named import from an ESM-syntax build that Node.js thinks is CJS:
|
|
94
|
+
|
|
95
|
+
```bash [Terminal]
|
|
96
|
+
file:///path/to/index.mjs:5
|
|
97
|
+
import { named } from 'sample-library'
|
|
98
|
+
^^^^^
|
|
99
|
+
SyntaxError: Named export 'named' not found. The requested module 'sample-library' is a CommonJS module, which may not support all module.exports as named exports.
|
|
100
|
+
|
|
101
|
+
CommonJS modules can always be imported via the default export, for example using:
|
|
102
|
+
|
|
103
|
+
import pkg from 'sample-library';
|
|
104
|
+
const { named } = pkg;
|
|
105
|
+
|
|
106
|
+
at ModuleJob._instantiate (internal/modules/esm/module_job.js:120:21)
|
|
107
|
+
at async ModuleJob.run (internal/modules/esm/module_job.js:165:5)
|
|
108
|
+
at async Loader.import (internal/modules/esm/loader.js:177:24)
|
|
109
|
+
at async Object.loadESM (internal/process/esm_loader.js:68:5)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Troubleshooting ESM Issues
|
|
113
|
+
|
|
114
|
+
If you encounter these errors, the issue is almost certainly with the upstream library. They need to [fix their library](#library-author-guide) to support being imported by Node.
|
|
115
|
+
|
|
116
|
+
### Transpiling Libraries
|
|
117
|
+
|
|
118
|
+
In the meantime, you can tell Nuxt not to try to import these libraries by adding them to `build.transpile`:
|
|
119
|
+
|
|
120
|
+
```ts twoslash
|
|
121
|
+
export default defineNuxtConfig({
|
|
122
|
+
build: {
|
|
123
|
+
transpile: ['sample-library']
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
You may find that you _also_ need to add other packages that are being imported by these libraries.
|
|
129
|
+
|
|
130
|
+
### Aliasing Libraries
|
|
131
|
+
|
|
132
|
+
In some cases, you may also need to manually alias the library to the CJS version, for example:
|
|
133
|
+
|
|
134
|
+
```ts twoslash
|
|
135
|
+
export default defineNuxtConfig({
|
|
136
|
+
alias: {
|
|
137
|
+
'sample-library': 'sample-library/dist/sample-library.cjs.js'
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Default Exports
|
|
143
|
+
|
|
144
|
+
A dependency with CommonJS format, can use `module.exports` or `exports` to provide a default export:
|
|
145
|
+
|
|
146
|
+
```js [node_modules/cjs-pkg/index.js]
|
|
147
|
+
module.exports = { test: 123 }
|
|
148
|
+
// or
|
|
149
|
+
exports.test = 123
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
This normally works well if we `require` such dependency:
|
|
153
|
+
|
|
154
|
+
```js [test.cjs]
|
|
155
|
+
const pkg = require('cjs-pkg')
|
|
156
|
+
|
|
157
|
+
console.log(pkg) // { test: 123 }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
[Node.js in native ESM mode](https://nodejs.org/api/esm.html#interoperability-with-commonjs), [typescript with `esModuleInterop` enabled](https://www.typescriptlang.org/tsconfig#esModuleInterop) and bundlers such as webpack, provide a compatibility mechanism so that we can default import such library.
|
|
161
|
+
This mechanism is often referred to as "interop require default":
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
import pkg from 'cjs-pkg'
|
|
165
|
+
|
|
166
|
+
console.log(pkg) // { test: 123 }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
However, because of the complexities of syntax detection and different bundle formats, there is always a chance that the interop default fails and we end up with something like this:
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
import pkg from 'cjs-pkg'
|
|
173
|
+
|
|
174
|
+
console.log(pkg) // { default: { test: 123 } }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Also when using dynamic import syntax (in both CJS and ESM files), we always have this situation:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
import('cjs-pkg').then(console.log) // [Module: null prototype] { default: { test: '123' } }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
In this case, we need to manually interop the default export:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
// Static import
|
|
187
|
+
import { default as pkg } from 'cjs-pkg'
|
|
188
|
+
|
|
189
|
+
// Dynamic import
|
|
190
|
+
import('cjs-pkg').then(m => m.default || m).then(console.log)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
For handling more complex situations and more safety, we recommend and internally use [mlly](https://github.com/unjs/mlly) in Nuxt that can preserve named exports.
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
import { interopDefault } from 'mlly'
|
|
197
|
+
|
|
198
|
+
// Assuming the shape is { default: { foo: 'bar' }, baz: 'qux' }
|
|
199
|
+
import myModule from 'my-module'
|
|
200
|
+
|
|
201
|
+
console.log(interopDefault(myModule)) // { foo: 'bar', baz: 'qux' }
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Library Author Guide
|
|
205
|
+
|
|
206
|
+
The good news is that it's relatively simple to fix issues of ESM compatibility. There are two main options:
|
|
207
|
+
|
|
208
|
+
1. **You can rename your ESM files to end with `.mjs`.**
|
|
209
|
+
|
|
210
|
+
_This is the recommended and simplest approach._ You may have to sort out issues with your library's dependencies and possibly with your build system, but in most cases, this should fix the problem for you. It's also recommended to rename your CJS files to end with `.cjs`, for the greatest explicitness.
|
|
211
|
+
|
|
212
|
+
1. **You can opt to make your entire library ESM-only**.
|
|
213
|
+
|
|
214
|
+
This would mean setting `"type": "module"` in your `package.json` and ensuring that your built library uses ESM syntax. However, you may face issues with your dependencies - and this approach means your library can _only_ be consumed in an ESM context.
|
|
215
|
+
|
|
216
|
+
### Migration
|
|
217
|
+
|
|
218
|
+
The initial step from CJS to ESM is updating any usage of `require` to use `import` instead:
|
|
219
|
+
|
|
220
|
+
::code-group
|
|
221
|
+
|
|
222
|
+
```js [Before]
|
|
223
|
+
module.exports = ...
|
|
224
|
+
|
|
225
|
+
exports.hello = ...
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```js [After]
|
|
229
|
+
export default ...
|
|
230
|
+
|
|
231
|
+
export const hello = ...
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
::
|
|
235
|
+
|
|
236
|
+
::code-group
|
|
237
|
+
|
|
238
|
+
```js [Before]
|
|
239
|
+
const myLib = require('my-lib')
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```js [After]
|
|
243
|
+
import myLib from 'my-lib'
|
|
244
|
+
// or
|
|
245
|
+
const myLib = await import('my-lib').then(lib => lib.default || lib)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
::
|
|
249
|
+
|
|
250
|
+
In ESM Modules, unlike CJS, `require`, `require.resolve`, `__filename` and `__dirname` globals are not available
|
|
251
|
+
and should be replaced with `import()` and `import.meta.filename`.
|
|
252
|
+
|
|
253
|
+
::code-group
|
|
254
|
+
|
|
255
|
+
```js [Before]
|
|
256
|
+
import { join } from 'path'
|
|
257
|
+
|
|
258
|
+
const newDir = join(__dirname, 'new-dir')
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```js [After]
|
|
262
|
+
import { fileURLToPath } from 'node:url'
|
|
263
|
+
|
|
264
|
+
const newDir = fileURLToPath(new URL('./new-dir', import.meta.url))
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
::
|
|
268
|
+
|
|
269
|
+
::code-group
|
|
270
|
+
|
|
271
|
+
```js [Before]
|
|
272
|
+
const someFile = require.resolve('./lib/foo.js')
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```js [After]
|
|
276
|
+
import { resolvePath } from 'mlly'
|
|
277
|
+
|
|
278
|
+
const someFile = await resolvePath('my-lib', { url: import.meta.url })
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
::
|
|
282
|
+
|
|
283
|
+
### Best Practices
|
|
284
|
+
|
|
285
|
+
- Prefer named exports rather than default export. This helps reduce CJS conflicts. (see [Default exports](#default-exports) section)
|
|
286
|
+
|
|
287
|
+
- Avoid depending on Node.js built-ins and CommonJS or Node.js-only dependencies as much as possible to make your library usable in Browsers and Edge Workers without needing Nitro polyfills.
|
|
288
|
+
|
|
289
|
+
- Use new `exports` field with conditional exports. ([read more](https://nodejs.org/api/packages.html#conditional-exports)).
|
|
290
|
+
|
|
291
|
+
```json
|
|
292
|
+
{
|
|
293
|
+
"exports": {
|
|
294
|
+
".": {
|
|
295
|
+
"import": "./dist/mymodule.mjs"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|