From 32336a6f53c7b31d0d1cf933ac596135af5564df Mon Sep 17 00:00:00 2001 From: Aral Roca Gomez Date: Sun, 1 Dec 2024 23:01:02 +0100 Subject: [PATCH] feat: add `output: 'deno'` (#657) * docs: add deno docs * fix: avoid warning action log in deno * fix: change some vars to support deno --- docs/api-reference/compiler-apis/compileWC.md | 28 ++++---- .../server-apis/fileSystemRouter.md | 20 +++--- .../building/deno-server.md | 49 +++++++++++++ .../building/index.md | 13 ++-- .../configuring/output.md | 20 +++++- .../configuring/zig-rust-c-files.md | 2 +- .../routing/websockets.md | 26 +++---- .../with-api-routes/src/pages/about/index.tsx | 8 +-- .../with-elysia/src/pages/about/index.tsx | 8 +-- .../src/pages/about/index.tsx | 8 +-- examples/with-i18n/src/i18n/messages/en.ts | 2 +- examples/with-i18n/src/i18n/messages/es.ts | 2 +- .../with-middleware/src/pages/about/index.tsx | 8 +-- .../src/pages/about/index.tsx | 8 +-- .../src/pages/about/index.tsx | 8 +-- .../with-suspense/src/pages/about/index.tsx | 8 +-- packages/brisa/src/cli/build.ts | 8 +-- packages/brisa/src/cli/dev-live-reload.tsx | 6 +- .../src/cli/serve/serve-options.test.tsx | 24 +++++++ .../brisa/src/cli/serve/serve-options.tsx | 2 +- packages/brisa/src/types/index.d.ts | 5 +- .../src/utils/compile-files/index.test.ts | 9 ++- .../brisa/src/utils/compile-files/index.ts | 4 +- .../index.ts | 23 +++++-- .../src/utils/file-system-router/index.ts | 2 +- .../index.test.ts | 2 +- .../get-readable-stream-from-path/index.ts | 2 +- .../src/utils/runtime-version/index.test.ts | 23 +++++++ .../brisa/src/utils/runtime-version/index.ts | 15 ++++ .../server-component-plugin/index.test.ts | 54 +++++++++++++++ .../utils/server-component-plugin/index.ts | 2 +- .../src/utils/supports-basic-color/index.ts | 2 +- .../src/utils/transpile-actions/index.ts | 4 +- .../basic-template/pages/about/index.tsx | 8 +-- packages/www/src/config.ts | 4 ++ packages/www/src/public/content.json | 69 +++++++++++++++---- 36 files changed, 366 insertions(+), 120 deletions(-) create mode 100644 docs/building-your-application/building/deno-server.md create mode 100644 packages/brisa/src/utils/runtime-version/index.test.ts create mode 100644 packages/brisa/src/utils/runtime-version/index.ts diff --git a/docs/api-reference/compiler-apis/compileWC.md b/docs/api-reference/compiler-apis/compileWC.md index 0117b1f14..658fcd414 100644 --- a/docs/api-reference/compiler-apis/compileWC.md +++ b/docs/api-reference/compiler-apis/compileWC.md @@ -24,7 +24,7 @@ The `compileWC` function transpiles a JSX web component to be compatible with th #### Returns -- The transpiled code of the web component. +- The transpiled code of the web component. ## Example @@ -51,7 +51,7 @@ console.log(finalCode); ## Outside Bun.js -This function is intended to be used within the [Bun](https://bun.sh/) runtime, as it uses the [Bun transpiler](https://bun.sh/docs/api/transpiler) to convert TSX to JS. However, if you want to use it in other environments, such as Node.js or in the browser, you can do so, but you will need to transpile the TSX to JS beforehand, for example with [`@swc/wasm-web`](https://swc.rs/docs/usage/wasm). +This function is intended to be used within the [Bun](https://bun.sh/) runtime, as it uses the [Bun transpiler](https://bun.sh/docs/api/transpiler) to convert TSX to JS. However, if you want to use it in other environments, such as Node.js, Deno or in the browser, you can do so, but you will need to transpile the TSX to JS beforehand, for example with [`@swc/wasm-web`](https://swc.rs/docs/usage/wasm). > [!IMPORTANT] > @@ -64,21 +64,21 @@ import { compileWC } from "brisa/compiler"; import initSwc, { transformSync } from "@swc/wasm-web"; async function main() { - await initSwc(); - const code = ` + await initSwc(); + const code = ` export default function MyComponent() { return
Hello World
; } `; - const transpiledCode = transformSync(code, { - jsc: { - parser: { - syntax: "typescript", - tsx: true, - }, - }, - }); - const finalCode = compileWC(transpiledCode.code); - console.log(finalCode); + const transpiledCode = transformSync(code, { + jsc: { + parser: { + syntax: "typescript", + tsx: true, + }, + }, + }); + const finalCode = compileWC(transpiledCode.code); + console.log(finalCode); } ``` diff --git a/docs/api-reference/server-apis/fileSystemRouter.md b/docs/api-reference/server-apis/fileSystemRouter.md index a8e81dcb7..094c12a99 100644 --- a/docs/api-reference/server-apis/fileSystemRouter.md +++ b/docs/api-reference/server-apis/fileSystemRouter.md @@ -18,7 +18,7 @@ pages The API of `fileSystemRouter` is the same API of [`Bun.FileSystemRouter`](https://bun.sh/docs/api/file-system-router) with some differences: -- You can also use the `fileSystemRouter` API in Node.js. +- You can also use the `fileSystemRouter` API in Node.js or Deno. - There are some fixes and improvements in the API. - The `fileSystemRouter` API (with Bun runtime) is faster than the `Bun.FileSystemRouter` API. @@ -47,17 +47,17 @@ The `fileSystemRouter` function creates a new instance of the file system router ## Example usage ```tsx -import path from 'node:path'; -import { fileSystemRouter } from 'brisa/server'; +import path from "node:path"; +import { fileSystemRouter } from "brisa/server"; const router = fileSystemRouter({ - dir: path.join(import.meta.dirname, 'pages'), + dir: path.join(import.meta.dirname, "pages"), }); -const matchedRoute = router.match('/blog/hello-world?foo=bar'); +const matchedRoute = router.match("/blog/hello-world?foo=bar"); if (matchedRoute) { - console.log(matchedRoute); + console.log(matchedRoute); // { // filePath: 'pages/blog/[slug].tsx', // kind: 'dynamic', @@ -95,11 +95,11 @@ The `routes` property is the entries of routes and file paths. > `routes` entries are in alphabetical order ```tsx -import path from 'node:path'; -import { fileSystemRouter } from 'brisa/server'; +import path from "node:path"; +import { fileSystemRouter } from "brisa/server"; const router = fileSystemRouter({ - dir: path.join(import.meta.dirname, 'pages'), + dir: path.join(import.meta.dirname, "pages"), }); console.log(router.routes); @@ -111,5 +111,3 @@ console.log(router.routes); // ['/settings', '/Users/aralroca/my-app/src/pages/settings.tsx'], // ] ``` - - diff --git a/docs/building-your-application/building/deno-server.md b/docs/building-your-application/building/deno-server.md new file mode 100644 index 000000000..bfb8c51bd --- /dev/null +++ b/docs/building-your-application/building/deno-server.md @@ -0,0 +1,49 @@ +--- +description: Learn how build a Deno Web Service App in Brisa +--- + +# Deno Server + +Brisa enables starting as a [Deno](https://deno.com/) Server to serve your app by changing the `output` to `deno`. It generates a [Deno](https://deno.com/) server that serves your application on the port 3000 by default, it can be changed with the flag `--port`. + +This server is capable of serving your application with all the features that Brisa offers, such as i18n, routing, server actions and middleware. + +> [!NOTE] +> +> You need a different `output` type than `bun` since during the build your application is optimized to be served on a Deno server. This means that we use `Deno.serve` and you can use `deno.json` at the root of your project to configure your Deno server and it will be moved inside the build folder. + +## Configuration _(Optional)_ + +To enable a web service application, change the output mode inside [`brisa.config.ts`](/building-your-application/configuring/brisa-config-js): + +```ts filename="brisa.config.ts" +import type { Configuration } from "brisa"; + +export default { + output: "deno", +} satisfies Configuration; +``` + +After running `brisa build`, Brisa will generate a Deno server that serves your application on the port 3000 by default. + +## Changing the port + +To change the port, you can use the flag `--port`: + +```sh +brisa start --port 8080 +``` + +> [!NOTE] +> +> The default port is `process.env.PORT` or `3000`. + +After running `brisa build`, Brisa will generate a Bun server that serves your application on the port 8080. + +> [!TIP] +> +> Although you can still use the Bun tooling to start your application in Deno, if you want, you can use `NODE_ENV=production deno build/server.js` to start your application with Deno without Brisa CLI. + +## Custom server + +If you want to use a custom server, you can follow this guide: [Custom Server](/building-your-application/configuring/custom-server#custom-server). diff --git a/docs/building-your-application/building/index.md b/docs/building-your-application/building/index.md index 88dd00608..4e462ad7b 100644 --- a/docs/building-your-application/building/index.md +++ b/docs/building-your-application/building/index.md @@ -1,11 +1,11 @@ --- description: Learn how to build your Brisa app to production prev: - text: 'Integrating Tailwind CSS' - link: '/building-your-application/integrations/tailwind-css' + text: "Integrating Tailwind CSS" + link: "/building-your-application/integrations/tailwind-css" next: - text: 'Web Service App' - link: '/building-your-application/building/web-service-app' + text: "Web Service App" + link: "/building-your-application/building/web-service-app" --- # Building @@ -37,12 +37,15 @@ Brisa can be deployed to any hosting provider that supports Bun. Ensure your `pa Then, run `bun run build` to build your application. Finally, run `bun run start` to start the Bun server. This server supports all Brisa features. +But if you need Node.js or Deno, we support that too, you just have to configure it. See the different build strategies in the next point. + ## App Strategy (Static, Server, Desktop, Android, iOS) Brisa supports multiple [output](/building-your-application/configuring/output) strategies to build your application. You can choose between: - [Build a Bun Server App](/building-your-application/building/bun-server) - [Build a Node.js Server App](/building-your-application/building/node-server) +- [Build a Deno Server App](/building-your-application/building/deno-server) - [Build a Static Site App](/building-your-application/building/static-site-app) - [Build a Desktop App](/building-your-application/building/desktop-app) - [Build a Android App](/building-your-application/building/android-app) @@ -52,4 +55,4 @@ Brisa supports multiple [output](/building-your-application/configuring/output) Brisa is more than a framework; it is a **Web Component Compiler**. You can create web components using Brisa and build them to create a library. -- [Web Component Compiler](/building-your-application/building/web-component-compiler) \ No newline at end of file +- [Web Component Compiler](/building-your-application/building/web-component-compiler) diff --git a/docs/building-your-application/configuring/output.md b/docs/building-your-application/configuring/output.md index e632b9dfc..626f2e1d8 100644 --- a/docs/building-your-application/configuring/output.md +++ b/docs/building-your-application/configuring/output.md @@ -4,7 +4,7 @@ description: Learn how to build with different types of outputs # Output -Brisa, offers versatile output configuration options to tailor your build output according to your deployment needs. The `output` configuration property in `brisa.config.ts` allows you to define the type of output you desire, with options such as `server`, `static`, and `desktop`. +Brisa, offers versatile output configuration options to tailor your build output according to your deployment needs. The `output` configuration property in `brisa.config.ts` allows you to define the type of output you desire, with options such as `bun`, `node`, `deno`, `static`, `desktop`, `android` and `ios`. ## Understanding Output Types @@ -41,6 +41,22 @@ export default { > > You can use specific Bun.js features only related with building the application, like Macros, but not runtime features like [`bun:ffi`](/building-your-application/configuring/zig-rust-c-files), for that you need to find the equivalent in Node.js. +### 2. Deno Server Output (`deno`) + +The `deno` output type is designed for creating deployable Deno applications. To configure your Brisa project for Deno server output, adjust your `brisa.config.ts` as follows: + +```ts +import type { Configuration } from "brisa"; + +export default { + output: "deno", +} satisfies Configuration; +``` + +> [!NOTE] +> +> You can use specific Bun.js features only related with building the application, like Macros, but not runtime features like [`bun:ffi`](/building-your-application/configuring/zig-rust-c-files), for that you need to find the equivalent in Deno. + ### 3. Static Output (`static`) The `static` output type creates a static export suitable for deployment to static hosting services. To configure your Brisa project for static output, adjust your `brisa.config.ts` as follows: @@ -158,4 +174,4 @@ To view the changes in the output, run the `brisa build` command. In the case of > [!TIP] > -> If your application requires server-side features, like middleware or API endpoints, opt for the `server` output. For static websites, select the `static` output, and for desktop applications integrated with Tauri, use the `desktop` output. +> If your application requires server-side features, like middleware or API endpoints, opt for the `bun` / `node` / `deno` output. For static websites, select the `static` output, and for desktop / mobile applications integrated with Tauri, use the `desktop` / `ios` / `android` output. diff --git a/docs/building-your-application/configuring/zig-rust-c-files.md b/docs/building-your-application/configuring/zig-rust-c-files.md index 47b608419..cf1caaa49 100644 --- a/docs/building-your-application/configuring/zig-rust-c-files.md +++ b/docs/building-your-application/configuring/zig-rust-c-files.md @@ -29,7 +29,7 @@ pub extern "C" fn add(a: isize, b: isize) -> isize { > [!CAUTION] > -> If you are using `node` as output, this documentation does not apply. You need to find the equivalent in Node.js. +> If you are using `node` or `deno` as output, this documentation does not apply. You need to find the equivalent in the specific JS runtime. ## Compile Your Files diff --git a/docs/building-your-application/routing/websockets.md b/docs/building-your-application/routing/websockets.md index 52f71b0c2..59b68b5c1 100644 --- a/docs/building-your-application/routing/websockets.md +++ b/docs/building-your-application/routing/websockets.md @@ -14,7 +14,7 @@ Brisa supports server-side WebSockets, with on-the-fly compression, TLS support, > [!CAUTION] > -> This WebSockets documentation **only works** with the **Bun.js runtime**. If you want to use Node.js as output you will have to implement it with some library in this same file, [look here how to do it](#websockets-in-node-js). +> This WebSockets documentation **only works** with the **Bun.js runtime**. If you want to use Node.js or Deno as output you will have to implement it with some library in this same file, [look here how to do it](#websockets-in-node-js). ## Start a WebSocket server API @@ -250,37 +250,37 @@ ws.close(); ws.close(1000, "Closing connection gracefully"); ``` -## WebSockets in Node.js +## WebSockets in other JS runtimes (Node / Deno) -If you want to use WebSockets in a Node.js environment, you can use the [ws](https://github.com/websockets/ws) library. Here is an example of how to create a WebSocket server using the `ws` library in the `src/websocket.ts` file: +If you want to use WebSockets in a Node.js or Deno environment, you can use the [ws](https://github.com/websockets/ws) library. Here is an example of how to create a WebSocket server using the `ws` library in the `src/websocket.ts` file: **`src/websocket.ts`** ```ts -const WebSocket = require('ws'); +const WebSocket = require("ws"); // Create a WebSocket server const wss = new WebSocket.Server({ port: 8080 }); -wss.on('connection', function connection(ws) { +wss.on("connection", function connection(ws) { // Log a message when a new client connects - console.log('A new client connected!'); - + console.log("A new client connected!"); + // Receive messages from the client - ws.on('message', function incoming(message) { - console.log('Received:', message); - + ws.on("message", function incoming(message) { + console.log("Received:", message); + // Send a response back to the client ws.send(`You said: ${message}`); }); // Log a message when the client disconnects - ws.on('close', () => { - console.log('Client has disconnected'); + ws.on("close", () => { + console.log("Client has disconnected"); }); }); ``` > [!NOTE] > -> This `src/websocket.ts` file is loaded once when the server is created, if the module exports the `attach`, `message`, `open`, `close`, and `drain` functions, they will only be used in Bun.js, but when the file is executed in Node.js, the `ws` functions can be used to create a WebSocket server in Node.js. \ No newline at end of file +> This `src/websocket.ts` file is loaded once when the server is created, if the module exports the `attach`, `message`, `open`, `close`, and `drain` functions, they will only be used in Bun.js, but when the file is executed in other JS runtimes, the `ws` functions can be used to create a WebSocket server. diff --git a/examples/with-api-routes/src/pages/about/index.tsx b/examples/with-api-routes/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-api-routes/src/pages/about/index.tsx +++ b/examples/with-api-routes/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-elysia/src/pages/about/index.tsx b/examples/with-elysia/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-elysia/src/pages/about/index.tsx +++ b/examples/with-elysia/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-external-web-component/src/pages/about/index.tsx b/examples/with-external-web-component/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-external-web-component/src/pages/about/index.tsx +++ b/examples/with-external-web-component/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-i18n/src/i18n/messages/en.ts b/examples/with-i18n/src/i18n/messages/en.ts index f696a6e8d..581332e98 100644 --- a/examples/with-i18n/src/i18n/messages/en.ts +++ b/examples/with-i18n/src/i18n/messages/en.ts @@ -28,7 +28,7 @@ export default { 'Brisa not only uses Hypermedia, it streams it over the wire.', 'Brisa is also the only framework with full Internationalization support. not only routing, but you can also translate your pages and the URL pathnames if you need it. If you use i18n, the server components are 0 Bytes, but in Web Components are 800 B. At the end we use the Web Platform; we make a bridge with the ECMAScript Intl API to make it easier for you to translate your Web Components.', "In Brisa we like the idea that all the tooling is integrated, that's why Brisa is made with Bun we have extended the Matchers and added an API so you can run with Bun the tests of your Components.", - 'Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js if you want, generate a static output and upload it to a CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform thanks to its integration with Tauri.', + 'Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js or Deno if you want, generate a static output and upload it to a CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform thanks to its integration with Tauri.', 'We support Partial Prerendering, you can prerender only a part of your page, such as the footer.', 'We also support many more features like middleware, layouts, WebSockets, API routes, suspense, etc.', 'Brisa is the future of the Web, and the future is now. We invite you to try it and contribute to the community.', diff --git a/examples/with-i18n/src/i18n/messages/es.ts b/examples/with-i18n/src/i18n/messages/es.ts index fd9040d38..031bf648d 100644 --- a/examples/with-i18n/src/i18n/messages/es.ts +++ b/examples/with-i18n/src/i18n/messages/es.ts @@ -27,7 +27,7 @@ export default { 'Brisa no solo usa Hypermedia, sino que la transmite por la red.', 'Brisa también es el único framework con soporte completo de Internacionalización. No solo en el enrutamiento, sino que también puedes traducir tus páginas y los nombres de las rutas si lo necesitas. Si usas i18n, los componentes del servidor ocupan 0 Bytes, pero en los Web Components son 800 B. Al final, usamos la Plataforma Web; hacemos un puente con la API Intl de ECMAScript para facilitar la traducción de tus Web Components.', 'En Brisa nos gusta la idea de que todas las herramientas estén integradas, por eso Brisa está hecho con Bun. Hemos ampliado los Matchers y añadido una API para que puedas ejecutar con Bun los tests de tus Componentes.', - 'Bun es genial y mejora mucho la experiencia de desarrollo. Aunque recomendamos Bun.js también como runtime, como salida puedes usar Node.js si lo prefieres, generar una salida estática y subirla a un CDN, o generar una app ejecutable para Android (.apk), iOS (.ipa), Windows (.exe), Mac (.dmg), o Linux (.deb). Sí, Brisa es multiplataforma gracias a su integración con Tauri.', + 'Bun es genial y mejora mucho la experiencia de desarrollo. Aunque recomendamos Bun.js también como runtime, como salida puedes usar Node.js o Deno si lo prefieres, generar una salida estática y subirla a un CDN, o generar una app ejecutable para Android (.apk), iOS (.ipa), Windows (.exe), Mac (.dmg), o Linux (.deb). Sí, Brisa es multiplataforma gracias a su integración con Tauri.', 'Soportamos Pre-renderizado Parcial, puedes pre-renderizar solo una parte de tu página, como el pie de página.', 'También soportamos muchas más características como middleware, layouts, WebSockets, rutas API, suspense, etc.', 'Brisa es el futuro de la Web, y el futuro es ahora. Te invitamos a probarlo y a contribuir a la comunidad.', diff --git a/examples/with-middleware/src/pages/about/index.tsx b/examples/with-middleware/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-middleware/src/pages/about/index.tsx +++ b/examples/with-middleware/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-sqlite-with-server-action/src/pages/about/index.tsx b/examples/with-sqlite-with-server-action/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-sqlite-with-server-action/src/pages/about/index.tsx +++ b/examples/with-sqlite-with-server-action/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-streaming-list/src/pages/about/index.tsx b/examples/with-streaming-list/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-streaming-list/src/pages/about/index.tsx +++ b/examples/with-streaming-list/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/examples/with-suspense/src/pages/about/index.tsx b/examples/with-suspense/src/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/examples/with-suspense/src/pages/about/index.tsx +++ b/examples/with-suspense/src/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/packages/brisa/src/cli/build.ts b/packages/brisa/src/cli/build.ts index cef7a8158..d662652ba 100644 --- a/packages/brisa/src/cli/build.ts +++ b/packages/brisa/src/cli/build.ts @@ -6,10 +6,12 @@ import byteSizeToString from '@/utils/byte-size-to-string'; import { logTable, generateStaticExport } from './build-utils'; import compileBrisaInternalsToDoBuildPortable from '@/utils/compile-serve-internals-into-build'; import { log } from '@/utils/log/log-build'; +import runtimeVersion from '@/utils/runtime-version'; const outputText = { bun: 'Bun.js Web Service App', node: 'Node.js Server App', + deno: 'Deno Server App', static: 'Static Site App', android: 'Android App', ios: 'iOS App', @@ -33,11 +35,9 @@ export default async function build() { log( LOG_PREFIX.INFO, - `🚀 Brisa ${VERSION}:` + - (JS_RUNTIME === 'node' - ? ` Running on Node.js ${process.version}` - : ` Running on Bun.js ${Bun.version}`), + `🚀 Brisa ${VERSION}: Running on ${runtimeVersion(JS_RUNTIME)}`, ); + log( LOG_PREFIX.WAIT, IS_PRODUCTION diff --git a/packages/brisa/src/cli/dev-live-reload.tsx b/packages/brisa/src/cli/dev-live-reload.tsx index e7c53f4e1..7aa660651 100644 --- a/packages/brisa/src/cli/dev-live-reload.tsx +++ b/packages/brisa/src/cli/dev-live-reload.tsx @@ -11,7 +11,7 @@ const { LOG_PREFIX, SRC_DIR, IS_DEVELOPMENT, IS_SERVE_PROCESS } = constants; const LIVE_RELOAD_WEBSOCKET_PATH = '__brisa_live_reload__'; const LIVE_RELOAD_COMMAND = 'reload'; -// Similar than Bun.nanoseconds, but also working with Node.js +// Similar than Bun.nanoseconds, but also working with Node.js / Deno function nanoseconds() { return Number(process.hrtime.bigint()); } @@ -54,8 +54,8 @@ export async function activateHotReload() { // Note: we are using spawnSync instead of executing directly the build because // we prefer to separate both processes. In this way, serve can be executed in - // different runtimes, like Node.js or Bun, however, the build process is always - // executed in Bun. + // different runtimes, like Node.js, Deno or Bun, however, the build process is + // always executed in Bun. // https://github.com/brisa-build/brisa/issues/404 currentProcess = cp.spawn( process.execPath, diff --git a/packages/brisa/src/cli/serve/serve-options.test.tsx b/packages/brisa/src/cli/serve/serve-options.test.tsx index cc5b50706..969b8f763 100644 --- a/packages/brisa/src/cli/serve/serve-options.test.tsx +++ b/packages/brisa/src/cli/serve/serve-options.test.tsx @@ -1746,6 +1746,30 @@ describe.each(BASE_PATHS)('CLI: serve %s', (basePath) => { mockOpenInEditor.mockRestore(); }); + it('should not call Bun.openInEditor in Deno and return 404', async () => { + globalThis.mockConstants = { + ...globalThis.mockConstants, + IS_PRODUCTION: false, + IS_DEVELOPMENT: true, + JS_RUNTIME: 'deno', + }; + const mockOpenInEditor = spyOn(Bun, 'openInEditor').mockImplementation( + () => {}, + ); + const response = await testRequest( + new Request( + `http://localhost:1234/__brisa_dev_file__?file=${encodeURIComponent( + 'src/pages/somepage.tsx', + )}&line=1&column=1`, + { method: 'POST' }, + ), + ); + + expect(response.status).toBe(404); + expect(mockOpenInEditor).not.toHaveBeenCalled(); + mockOpenInEditor.mockRestore(); + }); + it('should open the editor calling /__brisa_dev_file__ with internal brisa file from build with line and column', async () => { globalThis.mockConstants = { ...globalThis.mockConstants, diff --git a/packages/brisa/src/cli/serve/serve-options.tsx b/packages/brisa/src/cli/serve/serve-options.tsx index 7cb112ac2..1c02cedf4 100644 --- a/packages/brisa/src/cli/serve/serve-options.tsx +++ b/packages/brisa/src/cli/serve/serve-options.tsx @@ -102,7 +102,7 @@ export async function getServeOptions() { if (JS_RUNTIME !== 'bun') { // Note: This only happens on development, and we use // the Bun runtime in development. Other runtimes like - // Node.js for now are only supported in production. + // Node.js / Deno for now are only supported in production. return new Response(null, { status: 404 }); } diff --git a/packages/brisa/src/types/index.d.ts b/packages/brisa/src/types/index.d.ts index 175254311..ac7d60836 100644 --- a/packages/brisa/src/types/index.d.ts +++ b/packages/brisa/src/types/index.d.ts @@ -38,7 +38,7 @@ export type InternalConstants = { ROOT_DIR: string; IS_PRODUCTION: boolean; IS_DEVELOPMENT: boolean; - JS_RUNTIME: 'bun' | 'node'; + JS_RUNTIME: 'bun' | 'node' | 'deno'; PAGE_404: string; PAGE_500: string; VERSION: string; @@ -1127,6 +1127,7 @@ export type Configuration = { * * - `bun`: The output is a Bun.js serve that can be deployed to a server. * - `node`: The output is a Node.js server that can be deployed to a server. + * - `deno`: The output is a Deno server that can be deployed to a server. * - `static`: The output is a static export that can be deployed to a static hosting. * - `desktop`: The output is a desktop app that can be deployed to a desktop. * - `android`: The output is an Android app that can be deployed to an Android device. @@ -1142,7 +1143,7 @@ export type Configuration = { * * - [How to use `output`](https://brisa.build/building-your-application/configuring/output) */ - output?: 'bun' | 'node' | 'static' | 'desktop' | 'android' | 'ios'; + output?: 'bun' | 'node' | 'deno' | 'static' | 'desktop' | 'android' | 'ios'; /** * Description: diff --git a/packages/brisa/src/utils/compile-files/index.test.ts b/packages/brisa/src/utils/compile-files/index.test.ts index c73c2f4af..056f21ae6 100644 --- a/packages/brisa/src/utils/compile-files/index.test.ts +++ b/packages/brisa/src/utils/compile-files/index.test.ts @@ -80,7 +80,10 @@ describe('utils', () => { }); expect(logs).toBeEmpty(); expect(success).toBe(true); - expect(mockConsoleLog).toHaveBeenCalledTimes(0); + // 2 logs also working in dev: + // [ wait ] compiling 2 server entrypoints... + // [ wait ] analyzing and preparing client build... + expect(mockConsoleLog).toHaveBeenCalledTimes(2); expect(files).toHaveLength(3); expect(files[0]).toBe('_brisa'); expect(files[1]).toBe('pages'); @@ -967,7 +970,11 @@ describe('utils', () => { ); const info = constants.LOG_PREFIX.INFO; + const wait = constants.LOG_PREFIX.WAIT; const expected = minifyText(` + ${wait} compiling 1 server entrypoints... + ${wait} analyzing and preparing client build... + ${wait} compiling 1 client entrypoints... ${info} ${info}Route | JS server | JS client (gz) ${info}---------------------------------------------- diff --git a/packages/brisa/src/utils/compile-files/index.ts b/packages/brisa/src/utils/compile-files/index.ts index fb3da1d73..4706dddc9 100644 --- a/packages/brisa/src/utils/compile-files/index.ts +++ b/packages/brisa/src/utils/compile-files/index.ts @@ -26,7 +26,7 @@ export default async function compileFiles() { LOG_PREFIX, IS_STATIC_EXPORT, } = getConstants(); - const isNode = CONFIG.output === 'node' && IS_PRODUCTION; + const isBun = !CONFIG.output || CONFIG.output === 'bun' || !IS_PRODUCTION; const webComponentsDir = join(SRC_DIR, 'web-components'); const pagesDir = join(SRC_DIR, 'pages'); const apiDir = join(SRC_DIR, 'api'); @@ -78,7 +78,7 @@ export default async function compileFiles() { outdir: BUILD_DIR, sourcemap: IS_PRODUCTION ? undefined : 'inline', root: SRC_DIR, - target: isNode ? 'node' : 'bun', + target: isBun ? 'bun' : 'node', minify: IS_PRODUCTION, // splitting: false -> necessary to analyze the server pages // for the client build. FIXME: improve this to analyze each diff --git a/packages/brisa/src/utils/compile-serve-internals-into-build/index.ts b/packages/brisa/src/utils/compile-serve-internals-into-build/index.ts index 56a0abb3b..de9a963d8 100644 --- a/packages/brisa/src/utils/compile-serve-internals-into-build/index.ts +++ b/packages/brisa/src/utils/compile-serve-internals-into-build/index.ts @@ -4,7 +4,7 @@ import { getConstants } from '@/constants'; import { logBuildError } from '../log/log-build'; import getImportableFilepath from '../get-importable-filepath'; -const SERVER_OUTPUTS = new Set(['bun', 'node']); +const SERVER_OUTPUTS = new Set(['bun', 'node', 'deno']); const NO_SERVER_EXPORTS = new Set([ './client', './client-simplified', @@ -14,6 +14,17 @@ const NO_SERVER_EXPORTS = new Set([ './cli.js', ]); +const JS_RUNTIME_NAME: Record = { + node: 'Node.js', + deno: 'Deno', + default: 'Bun.js', +} as const; + +const JS_RUNTIME_CMD: Record = { + node: 'node', + deno: 'deno run', + default: 'bun run', +} as const; /** * This function move the brisa/cli/out/serve/index.js file into the build folder * and defining the ROOT_DIR, BUILD_DIR, WORKSPACE constants. @@ -40,9 +51,10 @@ export default async function compileServeInternalsIntoBuild() { 'serve', 'index.js', ); - const isNode = CONFIG.output === 'node'; - const runtimeName = isNode ? 'Node.js' : 'Bun.js'; - const runtimeExec = isNode ? 'node' : 'bun run'; + const isBun = !CONFIG.output || CONFIG.output === 'bun'; + const runtimeName = + JS_RUNTIME_NAME[CONFIG.output!] ?? JS_RUNTIME_NAME.default; + const runtimeExec = JS_RUNTIME_CMD[CONFIG.output!] ?? JS_RUNTIME_CMD.default; const entrypoints = []; const configImportPath = getImportableFilepath('brisa.config', ROOT_DIR); const isServer = IS_PRODUCTION && SERVER_OUTPUTS.has(CONFIG.output ?? 'bun'); @@ -68,7 +80,8 @@ export default async function compileServeInternalsIntoBuild() { entry: '[name].[ext]', }, external: CONFIG.external, - target: isNode ? 'node' : 'bun', + // Note: for Deno we need "node" as target too + target: isBun ? 'bun' : 'node', banner: [ 'process.env.IS_SERVE_PROCESS ??= true;', 'process.env.IS_PROD ??= true;', diff --git a/packages/brisa/src/utils/file-system-router/index.ts b/packages/brisa/src/utils/file-system-router/index.ts index e78c3f5e4..f05947dd7 100644 --- a/packages/brisa/src/utils/file-system-router/index.ts +++ b/packages/brisa/src/utils/file-system-router/index.ts @@ -26,7 +26,7 @@ const SYMBOLS = new Set([ '=', ]); -// Inspired on Bun.FileSystemRouter, but compatible with Node.js as well +// Inspired on Bun.FileSystemRouter, but compatible with Node.js/Deno as well export function fileSystemRouter(options: FileSystemRouterOptions) { const routes = Object.entries(resolveRoutes(options)).sort( sortPathsBySegments, diff --git a/packages/brisa/src/utils/get-readable-stream-from-path/index.test.ts b/packages/brisa/src/utils/get-readable-stream-from-path/index.test.ts index 492e2b275..e96410384 100644 --- a/packages/brisa/src/utils/get-readable-stream-from-path/index.test.ts +++ b/packages/brisa/src/utils/get-readable-stream-from-path/index.test.ts @@ -5,7 +5,7 @@ import getReadableStreamFromPath from '.'; const FIXTURES_PATH = path.join(import.meta.dir, '..', '..', '__fixtures__'); describe('utils/get-readable-stream-from-path', () => { - describe('Node.js runtime', () => { + describe('Node.js / Deno runtime', () => { it('should return a ReadableStream from a file path', () => { const filePath = path.join(FIXTURES_PATH, 'public', 'favicon.ico'); const stream = getReadableStreamFromPath(filePath, false); diff --git a/packages/brisa/src/utils/get-readable-stream-from-path/index.ts b/packages/brisa/src/utils/get-readable-stream-from-path/index.ts index 85b4d094f..383dbe5d6 100644 --- a/packages/brisa/src/utils/get-readable-stream-from-path/index.ts +++ b/packages/brisa/src/utils/get-readable-stream-from-path/index.ts @@ -14,7 +14,7 @@ export default function getReadableStreamFromPath( return Bun.file(filePath).stream(); } - // Node.js runtime + // Node.js / Deno runtime const readStream = fs.createReadStream(filePath); return new ReadableStream({ diff --git a/packages/brisa/src/utils/runtime-version/index.test.ts b/packages/brisa/src/utils/runtime-version/index.test.ts new file mode 100644 index 000000000..aab94c5c5 --- /dev/null +++ b/packages/brisa/src/utils/runtime-version/index.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it, beforeEach, afterEach } from 'bun:test'; +import runtimeVersion from '.'; + +describe('runtimeVersion', () => { + beforeEach(() => { + // @ts-ignore + globalThis.Deno = { + version: { deno: '1.0.0' }, + }; + }); + + afterEach(() => { + // @ts-ignore + delete globalThis.Deno; + }); + + it('should return the correct runtime version', () => { + expect(runtimeVersion('node')).toBe(`Node.js ${process.version}`); + // @ts-ignore + expect(runtimeVersion('deno')).toBe(`Deno ${Deno.version.deno}`); + expect(runtimeVersion('bun')).toBe(`Bun.js ${Bun.version}`); + }); +}); diff --git a/packages/brisa/src/utils/runtime-version/index.ts b/packages/brisa/src/utils/runtime-version/index.ts new file mode 100644 index 000000000..cd31d45f6 --- /dev/null +++ b/packages/brisa/src/utils/runtime-version/index.ts @@ -0,0 +1,15 @@ +import type { InternalConstants } from '../../types'; + +export default function runtimeVersion( + jsRuntime: InternalConstants['JS_RUNTIME'], +) { + if (jsRuntime === 'node') { + return `Node.js ${process.version}`; + } + if (jsRuntime === 'deno') { + // @ts-ignore + return `Deno ${Deno.version.deno}`; + } + + return `Bun.js ${Bun.version}`; +} diff --git a/packages/brisa/src/utils/server-component-plugin/index.test.ts b/packages/brisa/src/utils/server-component-plugin/index.test.ts index f505cd23b..6df32ca84 100644 --- a/packages/brisa/src/utils/server-component-plugin/index.test.ts +++ b/packages/brisa/src/utils/server-component-plugin/index.test.ts @@ -595,6 +595,60 @@ describe('utils', () => { expect(logs).toContain(`The warn arises in: ${serverComponentPath}`); }); + it('should NOT warn in DEV when there are actions and the config.output is "node"', () => { + const code = ` + export default function ServerComponent1() { + return

console.log('foo')} />; + } + + export function ServerComponent2({ onFoo }) { + return
; + } + `; + const mockConsoleLog = spyOn(console, 'log'); + globalThis.mockConstants = { + ...getConstants(), + CONFIG: { + output: 'node', + }, + }; + const out = serverComponentPlugin(code, { + allWebComponents: {}, + fileID: 'a1', + path: serverComponentPath, + }); + + expect(out.hasActions).toBeTrue(); + expect(mockConsoleLog).not.toHaveBeenCalled(); + }); + + it('should NOT warn in DEV when there are actions and the config.output is "deno"', () => { + const code = ` + export default function ServerComponent1() { + return
console.log('foo')} />; + } + + export function ServerComponent2({ onFoo }) { + return
; + } + `; + const mockConsoleLog = spyOn(console, 'log'); + globalThis.mockConstants = { + ...getConstants(), + CONFIG: { + output: 'deno', + }, + }; + const out = serverComponentPlugin(code, { + allWebComponents: {}, + fileID: 'a1', + path: serverComponentPath, + }); + + expect(out.hasActions).toBeTrue(); + expect(mockConsoleLog).not.toHaveBeenCalled(); + }); + it('should not warn in PROD when there are actions and the config.output is "desktop"', () => { const code = ` export default function ServerComponent1() { diff --git a/packages/brisa/src/utils/server-component-plugin/index.ts b/packages/brisa/src/utils/server-component-plugin/index.ts index 4c154dfb7..edb5d890d 100644 --- a/packages/brisa/src/utils/server-component-plugin/index.ts +++ b/packages/brisa/src/utils/server-component-plugin/index.ts @@ -15,7 +15,7 @@ type ServerComponentPluginOptions = { }; const { parseCodeToAST, generateCodeFromAST } = AST('tsx'); -const SERVER_OUPUTS = new Set(['bun', 'node']); +const SERVER_OUPUTS = new Set(['bun', 'node', 'deno']); const WEB_COMPONENT_REGEX = /.*[\/\\]web-components[\/\\].*/; const FN_EXPRESSIONS = new Set([ 'ArrowFunctionExpression', diff --git a/packages/brisa/src/utils/supports-basic-color/index.ts b/packages/brisa/src/utils/supports-basic-color/index.ts index 224e23157..07265e9ad 100644 --- a/packages/brisa/src/utils/supports-basic-color/index.ts +++ b/packages/brisa/src/utils/supports-basic-color/index.ts @@ -25,5 +25,5 @@ export default function isANSIColorsSupported() { return env.TERM !== 'dumb'; } -// Similar than Bun.enableANSIColors but also available in Node.js +// Similar than Bun.enableANSIColors but also available in Node.js / Deno export const enableANSIColors = isANSIColorsSupported(); diff --git a/packages/brisa/src/utils/transpile-actions/index.ts b/packages/brisa/src/utils/transpile-actions/index.ts index 3b10a8144..43a74099d 100644 --- a/packages/brisa/src/utils/transpile-actions/index.ts +++ b/packages/brisa/src/utils/transpile-actions/index.ts @@ -595,7 +595,7 @@ export async function buildActions({ define, }: CompileActionsParams) { const { BUILD_DIR, IS_PRODUCTION, CONFIG, LOG_PREFIX } = getConstants(); - const isNode = CONFIG.output === 'node' && IS_PRODUCTION; + const isBun = !CONFIG.output || CONFIG.output === 'bun' || !IS_PRODUCTION; const rawActionsDir = join(BUILD_DIR, 'actions_raw'); const barrelFile = join(rawActionsDir, 'index.ts'); @@ -614,7 +614,7 @@ export async function buildActions({ external, sourcemap: IS_PRODUCTION ? undefined : 'inline', root: rawActionsDir, - target: isNode ? 'node' : 'bun', + target: isBun ? 'bun' : 'node', minify: IS_PRODUCTION, splitting: true, define, diff --git a/packages/create-brisa/basic-template/pages/about/index.tsx b/packages/create-brisa/basic-template/pages/about/index.tsx index ca5f62c34..d20342d7c 100644 --- a/packages/create-brisa/basic-template/pages/about/index.tsx +++ b/packages/create-brisa/basic-template/pages/about/index.tsx @@ -79,10 +79,10 @@ export default function About() {

Bun is great and improves the development experience a lot. Although we recommend Bun.js also as runtime, as output you can use Node.js - if you want, generate a static output and upload it to a CDN, or - generate an executable app for Android (.apk),  iOS (.ipa),  Windows - (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is multiplatform - thanks to its integration with Tauri. + or Deno if you want, generate a static output and upload it to a + CDN, or generate an executable app for Android (.apk),  iOS (.ipa),  + Windows (.exe), Mac (.dmg), or Linux (.deb). Yes, Brisa is + multiplatform thanks to its integration with Tauri.

diff --git a/packages/www/src/config.ts b/packages/www/src/config.ts index c465d8f0e..81c686a7e 100644 --- a/packages/www/src/config.ts +++ b/packages/www/src/config.ts @@ -315,6 +315,10 @@ export default { text: 'Node.js Server', link: '/building-your-application/building/node-server', }, + { + text: 'Deno Server', + link: '/building-your-application/building/deno-server', + }, { text: 'Desktop app', link: '/building-your-application/building/desktop-app', diff --git a/packages/www/src/public/content.json b/packages/www/src/public/content.json index 56cb372c3..9f3649c0f 100644 --- a/packages/www/src/public/content.json +++ b/packages/www/src/public/content.json @@ -258,7 +258,7 @@ { "id": "/api-reference/compiler-apis/compileWC#outside-bunjs", "title": "Outside Bun.js", - "text": "This function is intended to be used within the Bun runtime, as it uses the Bun transpiler to convert TSX to JS. However, if you want to use it in other environments, such as Node.js or in the browser, you can do so, but you will need to transpile the TSX to JS beforehand, for example with @swc/wasm-web. Bun.Transpiler is not applied when the environment is not Bun.js, so you will need to transpile the code before using compileWC to convert it to js.", + "text": "This function is intended to be used within the Bun runtime, as it uses the Bun transpiler to convert TSX to JS. However, if you want to use it in other environments, such as Node.js, Deno or in the browser, you can do so, but you will need to transpile the TSX to JS beforehand, for example with @swc/wasm-web. Bun.Transpiler is not applied when the environment is not Bun.js, so you will need to transpile the code before using compileWC to convert it to js.", "titles": [ "compileWC" ] @@ -266,7 +266,7 @@ { "id": "/api-reference/compiler-apis/compileWC#example-with-swcwasm-web", "title": "Example with @swc/wasm-web", - "text": "import { compileWC } from \"brisa/compiler\";\nimport initSwc, { transformSync } from \"@swc/wasm-web\";\n\nasync function main() {\n\tawait initSwc();\n\tconst code = `\n\t\texport default function MyComponent() { \n\t\t\treturn

Hello World
;\n\t\t}\n\t`;\n\tconst transpiledCode = transformSync(code, {\n\t\tjsc: {\n\t\t\tparser: {\n\t\t\t\tsyntax: \"typescript\",\n\t\t\t\ttsx: true,\n\t\t\t},\n\t\t},\n\t});\n\tconst finalCode = compileWC(transpiledCode.code);\n\tconsole.log(finalCode);\n}", + "text": "import { compileWC } from \"brisa/compiler\";\nimport initSwc, { transformSync } from \"@swc/wasm-web\";\n\nasync function main() {\n await initSwc();\n const code = `\n\t\texport default function MyComponent() { \n\t\t\treturn
Hello World
;\n\t\t}\n\t`;\n const transpiledCode = transformSync(code, {\n jsc: {\n parser: {\n syntax: \"typescript\",\n tsx: true,\n },\n },\n });\n const finalCode = compileWC(transpiledCode.code);\n console.log(finalCode);\n}", "titles": [ "compileWC", "Outside Bun.js" @@ -1336,7 +1336,7 @@ { "id": "/api-reference/server-apis/fileSystemRouter#filesystemrouter", "title": "fileSystemRouter", - "text": "The fileSystemRouter API is used to serve files from the file system. Internally, we use it for pages and API routes. pages\n├── index.tsx\n├── settings.tsx\n├── blog\n│ ├── [slug].tsx\n│ └── index.tsx\n└── [[...catchall]].tsx The API of fileSystemRouter is the same API of Bun.FileSystemRouter with some differences: You can also use the fileSystemRouter API in Node.js.\nThere are some fixes and improvements in the API.\nThe fileSystemRouter API (with Bun runtime) is faster than the Bun.FileSystemRouter API. The fileSystemRouter API is used internally by the Brisa server to serve files from the file system. However, you can also use it in your Custom Server.", + "text": "The fileSystemRouter API is used to serve files from the file system. Internally, we use it for pages and API routes. pages\n├── index.tsx\n├── settings.tsx\n├── blog\n│ ├── [slug].tsx\n│ └── index.tsx\n└── [[...catchall]].tsx The API of fileSystemRouter is the same API of Bun.FileSystemRouter with some differences: You can also use the fileSystemRouter API in Node.js or Deno.\nThere are some fixes and improvements in the API.\nThe fileSystemRouter API (with Bun runtime) is faster than the Bun.FileSystemRouter API. The fileSystemRouter API is used internally by the Brisa server to serve files from the file system. However, you can also use it in your Custom Server.", "titles": [] }, { @@ -1379,7 +1379,7 @@ { "id": "/api-reference/server-apis/fileSystemRouter#example-usage", "title": "Example usage", - "text": "import path from 'node:path';\nimport { fileSystemRouter } from 'brisa/server';\n\nconst router = fileSystemRouter({\n dir: path.join(import.meta.dirname, 'pages'),\n});\n\nconst matchedRoute = router.match('/blog/hello-world?foo=bar');\n\nif (matchedRoute) {\n console.log(matchedRoute); \n // {\n // filePath: 'pages/blog/[slug].tsx',\n // kind: 'dynamic',\n // name: '/blog/[slug]',\n // pathname: '/blog/hello-world',\n // src: 'blog/[slug].tsx',\n // params: { slug: 'hello-world' },\n // query: { foo: 'bar' },\n // }\n}", + "text": "import path from \"node:path\";\nimport { fileSystemRouter } from \"brisa/server\";\n\nconst router = fileSystemRouter({\n dir: path.join(import.meta.dirname, \"pages\"),\n});\n\nconst matchedRoute = router.match(\"/blog/hello-world?foo=bar\");\n\nif (matchedRoute) {\n console.log(matchedRoute);\n // {\n // filePath: 'pages/blog/[slug].tsx',\n // kind: 'dynamic',\n // name: '/blog/[slug]',\n // pathname: '/blog/hello-world',\n // src: 'blog/[slug].tsx',\n // params: { slug: 'hello-world' },\n // query: { foo: 'bar' },\n // }\n}", "titles": [ "fileSystemRouter" ] @@ -1404,7 +1404,7 @@ { "id": "/api-reference/server-apis/fileSystemRouter#routes-property", "title": "routes property", - "text": "The routes property is the entries of routes and file paths. routes entries are in alphabetical order import path from 'node:path';\nimport { fileSystemRouter } from 'brisa/server';\n\nconst router = fileSystemRouter({\n dir: path.join(import.meta.dirname, 'pages'),\n});\n\nconsole.log(router.routes);\n// [\n// ['/', '/Users/aralroca/my-app/src/pages/index.tsx'],\n// ['/[[...catchall]]', '/Users/aralroca/my-app/src/pages/[[...catchall]].tsx'],\n// ['/blog', '/Users/aralroca/my-app/src/pages/blog/index.tsx'],\n// ['/blog/[slug]', '/Users/aralroca/my-app/src/pages/blog/[slug].tsx'],\n// ['/settings', '/Users/aralroca/my-app/src/pages/settings.tsx'],\n// ]", + "text": "The routes property is the entries of routes and file paths. routes entries are in alphabetical order import path from \"node:path\";\nimport { fileSystemRouter } from \"brisa/server\";\n\nconst router = fileSystemRouter({\n dir: path.join(import.meta.dirname, \"pages\"),\n});\n\nconsole.log(router.routes);\n// [\n// ['/', '/Users/aralroca/my-app/src/pages/index.tsx'],\n// ['/[[...catchall]]', '/Users/aralroca/my-app/src/pages/[[...catchall]].tsx'],\n// ['/blog', '/Users/aralroca/my-app/src/pages/blog/index.tsx'],\n// ['/blog/[slug]', '/Users/aralroca/my-app/src/pages/blog/[slug].tsx'],\n// ['/settings', '/Users/aralroca/my-app/src/pages/settings.tsx'],\n// ]", "titles": [ "fileSystemRouter" ] @@ -1922,7 +1922,7 @@ { "id": "/building-your-application/building#bun-server", "title": "Bun Server", - "text": "Brisa can be deployed to any hosting provider that supports Bun. Ensure your package.json has the \"build\" and \"start\" scripts: {\n \"scripts\": {\n \"dev\": \"brisa dev\",\n \"build\": \"brisa build\",\n \"start\": \"brisa start\"\n }\n} Then, run bun run build to build your application. Finally, run bun run start to start the Bun server. This server supports all Brisa features.", + "text": "Brisa can be deployed to any hosting provider that supports Bun. Ensure your package.json has the \"build\" and \"start\" scripts: {\n \"scripts\": {\n \"dev\": \"brisa dev\",\n \"build\": \"brisa build\",\n \"start\": \"brisa start\"\n }\n} Then, run bun run build to build your application. Finally, run bun run start to start the Bun server. This server supports all Brisa features. But if you need Node.js or Deno, we support that too, you just have to configure it. See the different build strategies in the next point.", "titles": [ "Building", "Production Builds" @@ -1931,7 +1931,7 @@ { "id": "/building-your-application/building#app-strategy-static-server-desktop-android-ios", "title": "App Strategy (Static, Server, Desktop, Android, iOS)", - "text": "Brisa supports multiple output strategies to build your application. You can choose between: Build a Bun Server App\nBuild a Node.js Server App\nBuild a Static Site App\nBuild a Desktop App\nBuild a Android App\nBuild a iOS App", + "text": "Brisa supports multiple output strategies to build your application. You can choose between: Build a Bun Server App\nBuild a Node.js Server App\nBuild a Deno Server App\nBuild a Static Site App\nBuild a Desktop App\nBuild a Android App\nBuild a iOS App", "titles": [ "Building" ] @@ -1996,6 +1996,36 @@ "Bun Server" ] }, + { + "id": "/building-your-application/building/deno-server#deno-server", + "title": "Deno Server", + "text": "Brisa enables starting as a Deno Server to serve your app by changing the output to deno. It generates a Deno server that serves your application on the port 3000 by default, it can be changed with the flag --port. This server is capable of serving your application with all the features that Brisa offers, such as i18n, routing, server actions and middleware. You need a different output type than bun since during the build your application is optimized to be served on a Deno server. This means that we use Deno.serve and you can use deno.json at the root of your project to configure your Deno server and it will be moved inside the build folder.", + "titles": [] + }, + { + "id": "/building-your-application/building/deno-server#configuration-optional", + "title": "Configuration (Optional)", + "text": "To enable a web service application, change the output mode inside brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"deno\",\n} satisfies Configuration; After running brisa build, Brisa will generate a Deno server that serves your application on the port 3000 by default.", + "titles": [ + "Deno Server" + ] + }, + { + "id": "/building-your-application/building/deno-server#changing-the-port", + "title": "Changing the port", + "text": "To change the port, you can use the flag --port: brisa start --port 8080 The default port is process.env.PORT or 3000. After running brisa build, Brisa will generate a Bun server that serves your application on the port 8080. Although you can still use the Bun tooling to start your application in Deno, if you want, you can use NODE_ENV=production deno build/server.js to start your application with Deno without Brisa CLI.", + "titles": [ + "Deno Server" + ] + }, + { + "id": "/building-your-application/building/deno-server#custom-server", + "title": "Custom server", + "text": "If you want to use a custom server, you can follow this guide: Custom Server.", + "titles": [ + "Deno Server" + ] + }, { "id": "/building-your-application/building/desktop-app#desktop-app", "title": "Desktop app", @@ -3367,7 +3397,7 @@ { "id": "/building-your-application/configuring/output#output", "title": "Output", - "text": "Brisa, offers versatile output configuration options to tailor your build output according to your deployment needs. The output configuration property in brisa.config.ts allows you to define the type of output you desire, with options such as server, static, and desktop.", + "text": "Brisa, offers versatile output configuration options to tailor your build output according to your deployment needs. The output configuration property in brisa.config.ts allows you to define the type of output you desire, with options such as bun, node, deno, static, desktop, android and ios.", "titles": [] }, { @@ -3396,6 +3426,15 @@ "Understanding Output Types" ] }, + { + "id": "/building-your-application/configuring/output#2-deno-server-output-deno", + "title": "2. Deno Server Output (deno)", + "text": "The deno output type is designed for creating deployable Deno applications. To configure your Brisa project for Deno server output, adjust your brisa.config.ts as follows: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"deno\",\n} satisfies Configuration; You can use specific Bun.js features only related with building the application, like Macros, but not runtime features like bun:ffi, for that you need to find the equivalent in Deno.", + "titles": [ + "Output", + "Understanding Output Types" + ] + }, { "id": "/building-your-application/configuring/output#3-static-output-static", "title": "3. Static Output (static)", @@ -3435,7 +3474,7 @@ { "id": "/building-your-application/configuring/output#additional-considerations", "title": "Additional Considerations", - "text": "When configuring your output type, it's crucial to consider the deployment environment and requirements. Each output type serves a distinct purpose, and choosing the right one ensures optimal performance and compatibility. To view the changes in the output, run the brisa build command. In the case of server output, the build is generated in the build folder, while for static and desktop output, an additional out folder is created. The build folder is retained as it is needed to generate the initial build before generating static files or the desktop app in the separate out folder. Learn more details about static export here. If your application requires server-side features, like middleware or API endpoints, opt for the server output. For static websites, select the static output, and for desktop applications integrated with Tauri, use the desktop output.", + "text": "When configuring your output type, it's crucial to consider the deployment environment and requirements. Each output type serves a distinct purpose, and choosing the right one ensures optimal performance and compatibility. To view the changes in the output, run the brisa build command. In the case of server output, the build is generated in the build folder, while for static and desktop output, an additional out folder is created. The build folder is retained as it is needed to generate the initial build before generating static files or the desktop app in the separate out folder. Learn more details about static export here. If your application requires server-side features, like middleware or API endpoints, opt for the bun / node / deno output. For static websites, select the static output, and for desktop / mobile applications integrated with Tauri, use the desktop / ios / android output.", "titles": [ "Output" ] @@ -3482,7 +3521,7 @@ { "id": "/building-your-application/configuring/plugins#usage-in-bundler", "title": "Usage in bundler", - "text": "To use a plugin during the build, you must add it to the extendPlugins config in the brisa.config.ts file. Brisa will take care of running it for both the build of server files and the build of client files (web-components). import type { Configuration } from \"brisa\";\nimport { MyPlugin } from \"my-plugin\";\n\nexport default {\n extendPlugins(plugins, { dev, isServer, entrypoint }) {\n return [...plugins, MyPlugin];\n },\n} satisfies Configuration; Parameter\nType\nDescription\n\n\n\n\nplugins\nBunPlugin[]\nArray of plugins to extend with.\n\n\noptions\nExtendPluginOptions\nOptions (see table below) Options: Field\nType\nDescription\n\n\n\n\ndev\nboolean\nIndicates whether it's a development build.\n\n\nisServer\nboolean\nIndicates whether it's a server build.\n\n\nentrypoint\nstring | undefined\nEntry point for client builds, optional for servers. On the server it is only executed once and the build is with all the entrypoints, while on the client a separate build is made for each page, that's why on the client there is the entrypoint field in the options. A plugin is defined as simple JavaScript object containing a name property and a setup function. Example of one: import type { BunPlugin } from \"bun\";\n\nexport const myPlugin: BunPlugin = {\n name: \"Custom loader\",\n setup(build) {\n // implementation\n },\n}; To know more about bundler Bun plugins take a look at the Bun documentation. In the case you want to know how to load plugins in runtime (not recommended in Brisa), take a look at this Bun documentation.", + "text": "To use a plugin during the build, you must add it to the extendPlugins config in the brisa.config.ts file. Brisa will take care of running it for both the build of server files and the build of client files (web-components). import type { Configuration } from \"brisa\";\nimport { MyPlugin } from \"my-plugin\";\n\nexport default {\n extendPlugins(plugins, { dev, isServer }) {\n return [...plugins, MyPlugin];\n },\n} satisfies Configuration; Parameter\nType\nDescription\n\n\n\n\nplugins\nBunPlugin[]\nArray of plugins to extend with.\n\n\noptions\nExtendPluginOptions\nOptions (see table below) Options: Field\nType\nDescription\n\n\n\n\ndev\nboolean\nIndicates whether it's a development build.\n\n\nisServer\nboolean\nIndicates whether it's a server build. A plugin is defined as simple JavaScript object containing a name property and a setup function. Example of one: import type { BunPlugin } from \"bun\";\n\nexport const myPlugin: BunPlugin = {\n name: \"Custom loader\",\n setup(build) {\n // implementation\n },\n}; To know more about bundler Bun plugins take a look at the Bun documentation. In the case you want to know how to load plugins in runtime (not recommended in Brisa), take a look at this Bun documentation.", "titles": [ "Plugins" ] @@ -3600,7 +3639,7 @@ { "id": "/building-your-application/configuring/zig-rust-c-files#create-your-zig-rust-or-other-file", "title": "Create Your Zig, Rust, or Other File:", - "text": "Zig: // add.zig\npub export fn add(a: i32, b: i32) i32 {\n return a + b;\n} or with Rust: // add.rs\n#[no_mangle]\npub extern \"C\" fn add(a: isize, b: isize) -> isize {\n a + b\n} If you are using node as output, this documentation does not apply. You need to find the equivalent in Node.js.", + "text": "Zig: // add.zig\npub export fn add(a: i32, b: i32) i32 {\n return a + b;\n} or with Rust: // add.rs\n#[no_mangle]\npub extern \"C\" fn add(a: isize, b: isize) -> isize {\n a + b\n} If you are using node or deno as output, this documentation does not apply. You need to find the equivalent in the specific JS runtime.", "titles": [ "Use C ABI files (zig, rust, c/c++, c#, nim, kotlin...)" ] @@ -5241,7 +5280,7 @@ { "id": "/building-your-application/routing/websockets#real-time-communication-with-websockets", "title": "Real-time Communication with Websockets", - "text": "Websockets provide a powerful mechanism for establishing a full-duplex communication channel between a client and a server. This enables real-time updates and interactions in your application. Brisa supports server-side WebSockets, with on-the-fly compression, TLS support, and a Bun-native publish-subscribe API. Bun's WebSockets are fast, ~700,000 messages sent per second. This WebSockets documentation only works with the Bun.js runtime. If you want to use Node.js as output you will have to implement it with some library in this same file, look here how to do it.", + "text": "Websockets provide a powerful mechanism for establishing a full-duplex communication channel between a client and a server. This enables real-time updates and interactions in your application. Brisa supports server-side WebSockets, with on-the-fly compression, TLS support, and a Bun-native publish-subscribe API. Bun's WebSockets are fast, ~700,000 messages sent per second. This WebSockets documentation only works with the Bun.js runtime. If you want to use Node.js or Deno as output you will have to implement it with some library in this same file, look here how to do it.", "titles": [] }, { @@ -5379,9 +5418,9 @@ ] }, { - "id": "/building-your-application/routing/websockets#websockets-in-nodejs", - "title": "WebSockets in Node.js", - "text": "If you want to use WebSockets in a Node.js environment, you can use the ws library. Here is an example of how to create a WebSocket server using the ws library in the src/websocket.ts file: src/websocket.ts const WebSocket = require('ws');\n\n// Create a WebSocket server\nconst wss = new WebSocket.Server({ port: 8080 });\n\nwss.on('connection', function connection(ws) {\n // Log a message when a new client connects\n console.log('A new client connected!');\n \n // Receive messages from the client\n ws.on('message', function incoming(message) {\n console.log('Received:', message);\n \n // Send a response back to the client\n ws.send(`You said: ${message}`);\n });\n\n // Log a message when the client disconnects\n ws.on('close', () => {\n console.log('Client has disconnected');\n });\n}); This src/websocket.ts file is loaded once when the server is created, if the module exports the attach, message, open, close, and drain functions, they will only be used in Bun.js, but when the file is executed in Node.js, the ws functions can be used to create a WebSocket server in Node.js.", + "id": "/building-your-application/routing/websockets#websockets-in-other-js-runtimes-node-deno", + "title": "WebSockets in other JS runtimes (Node / Deno)", + "text": "If you want to use WebSockets in a Node.js or Deno environment, you can use the ws library. Here is an example of how to create a WebSocket server using the ws library in the src/websocket.ts file: src/websocket.ts const WebSocket = require(\"ws\");\n\n// Create a WebSocket server\nconst wss = new WebSocket.Server({ port: 8080 });\n\nwss.on(\"connection\", function connection(ws) {\n // Log a message when a new client connects\n console.log(\"A new client connected!\");\n\n // Receive messages from the client\n ws.on(\"message\", function incoming(message) {\n console.log(\"Received:\", message);\n\n // Send a response back to the client\n ws.send(`You said: ${message}`);\n });\n\n // Log a message when the client disconnects\n ws.on(\"close\", () => {\n console.log(\"Client has disconnected\");\n });\n}); This src/websocket.ts file is loaded once when the server is created, if the module exports the attach, message, open, close, and drain functions, they will only be used in Bun.js, but when the file is executed in other JS runtimes, the ws functions can be used to create a WebSocket server.", "titles": [ "Real-time Communication with Websockets" ]