From 9ef842557d8cab4f50aa97fb843b8f54432601e8 Mon Sep 17 00:00:00 2001 From: Aral Roca Date: Tue, 28 Jan 2025 00:20:04 +0100 Subject: [PATCH] chore: update meriyah --- bun.lock | 20 +++---- packages/brisa/package.json | 2 +- packages/www/package.json | 2 +- packages/www/src/public/content.json | 82 +++++++++++++++++----------- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/bun.lock b/bun.lock index 4cbd9151..04cdae23 100644 --- a/bun.lock +++ b/bun.lock @@ -25,7 +25,7 @@ "astring": "1.9.0", "csstype": "3.1.3", "diff-dom-streaming": "0.6.4", - "meriyah": "6.0.4", + "meriyah": "6.0.5", }, "devDependencies": { "@happy-dom/global-registrator": "15.11.7", @@ -88,7 +88,7 @@ "slugify": "1.6.6", }, "devDependencies": { - "@types/bun": "1.1.14", + "@types/bun": "1.2.0", "@types/jsdom": "21.1.7", "@types/mark.js": "8.11.12", "@types/markdown-it": "14.1.2", @@ -558,7 +558,7 @@ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "meriyah": ["meriyah@6.0.4", "", {}, "sha512-Hcas/D1O8qaRTb76L9jOHv0HXs83mJuaFjGcHnfrP2qlU+b/8XohHs2kDBNKejiiUihIFbSAFmLmBPNLUR9VLA=="], + "meriyah": ["meriyah@6.0.5", "", {}, "sha512-SrMqQCox7TTwtftWKHy/ZaVe+ZRpRl20pAgDo+PS9hzcAJrMjYsBJQPPiLXTnjztrqdfGS+Zz99r6Bwvydta1w=="], "microdiff": ["microdiff@1.3.2", "", {}, "sha512-pKy60S2febliZIbwdfEQKTtL5bLNxOyiRRmD400gueYl9XcHyNGxzHSlJWn9IMHwYXT0yohPYL08+bGozVk8cQ=="], @@ -744,7 +744,7 @@ "@vue/compiler-sfc/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], - "brisa/brisa": ["brisa@0.2.3", "", { "dependencies": { "astring": "1.9.0", "csstype": "3.1.3", "diff-dom-streaming": "0.6.4", "meriyah": "6.0.4" }, "bin": { "brisa": "index.js" } }, "sha512-4k4BrLb1FHYbf32NZ5FWRiPOwkbo3qzLsDeabWyq/ZfzwDI8Y6+FhsRW7qIb5ogZraUyVkC3cUF3e7EZKTbrmw=="], + "brisa/brisa": ["brisa@0.2.4", "", { "dependencies": { "astring": "1.9.0", "csstype": "3.1.3", "diff-dom-streaming": "0.6.4", "meriyah": "6.0.4" }, "bin": { "brisa": "index.js" } }, "sha512-iNF8ilEmFLELrotdZ/0ifqcP/xi76zNkIqEXkQ2EqvGR3vVK+A+SQjD+69ksfOfLG8xVZgtyxXOBxpouhNju6w=="], "brisa-tailwindcss/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], @@ -776,8 +776,6 @@ "update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "www/@types/bun": ["@types/bun@1.1.14", "", { "dependencies": { "bun-types": "1.1.37" } }, "sha512-opVYiFGtO2af0dnWBdZWlioLBoxSdDO5qokaazLhq8XQtGZbY4pY3/JxY8Zdf/hEwGubbp7ErZXoN1+h2yesxA=="], - "www/typescript": ["typescript@5.7.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg=="], "@pandacss/core/lightningcss/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], @@ -800,14 +798,12 @@ "@pandacss/core/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9KZZkmmy9oGDSrnyHuxP6iMhbsgChUiu/NSgOx+U1I/wTngBStDf2i2aGRCHvFqj19HqqBEI4WuGVQBa2V6e0A=="], - "search-engine-wc/brisa/diff-dom-streaming": ["diff-dom-streaming@0.6.1", "", {}, "sha512-zGhLBNF2MdNvndGc5HzEeC6/aMuIBBm7cv6GjFwBqwXFCGmgVOGBV139GsCBFpUHjc7lqaC1L9agiVbVMSLDdQ=="], + "brisa/brisa/meriyah": ["meriyah@6.0.4", "", {}, "sha512-Hcas/D1O8qaRTb76L9jOHv0HXs83mJuaFjGcHnfrP2qlU+b/8XohHs2kDBNKejiiUihIFbSAFmLmBPNLUR9VLA=="], - "search-engine-wc/brisa/meriyah": ["meriyah@6.0.1", "", {}, "sha512-OyvYIOgpzXREySYJ1cqEb2pOKdeQMTfF9M8dRU6nC4hi/GXMmNpe9ssZCrSoTHazu05BSAoRBN/uYeco+ymfOg=="], + "create-brisa/brisa/meriyah": ["meriyah@6.0.4", "", {}, "sha512-Hcas/D1O8qaRTb76L9jOHv0HXs83mJuaFjGcHnfrP2qlU+b/8XohHs2kDBNKejiiUihIFbSAFmLmBPNLUR9VLA=="], - "www/@types/bun/bun-types": ["bun-types@1.1.37", "", { "dependencies": { "@types/node": "~20.12.8", "@types/ws": "~8.5.10" } }, "sha512-C65lv6eBr3LPJWFZ2gswyrGZ82ljnH8flVE03xeXxKhi2ZGtFiO4isRKTKnitbSqtRAcaqYSR6djt1whI66AbA=="], - - "www/@types/bun/bun-types/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], + "search-engine-wc/brisa/diff-dom-streaming": ["diff-dom-streaming@0.6.1", "", {}, "sha512-zGhLBNF2MdNvndGc5HzEeC6/aMuIBBm7cv6GjFwBqwXFCGmgVOGBV139GsCBFpUHjc7lqaC1L9agiVbVMSLDdQ=="], - "www/@types/bun/bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], + "search-engine-wc/brisa/meriyah": ["meriyah@6.0.1", "", {}, "sha512-OyvYIOgpzXREySYJ1cqEb2pOKdeQMTfF9M8dRU6nC4hi/GXMmNpe9ssZCrSoTHazu05BSAoRBN/uYeco+ymfOg=="], } } diff --git a/packages/brisa/package.json b/packages/brisa/package.json index 248c7e6c..1a0fe65f 100644 --- a/packages/brisa/package.json +++ b/packages/brisa/package.json @@ -131,7 +131,7 @@ "astring": "1.9.0", "csstype": "3.1.3", "diff-dom-streaming": "0.6.4", - "meriyah": "6.0.4" + "meriyah": "6.0.5" }, "devDependencies": { "@happy-dom/global-registrator": "15.11.7", diff --git a/packages/www/package.json b/packages/www/package.json index 6befae55..64e20fe5 100644 --- a/packages/www/package.json +++ b/packages/www/package.json @@ -27,7 +27,7 @@ "@swc/wasm-web": "1.9.3" }, "devDependencies": { - "@types/bun": "1.1.14", + "@types/bun": "1.2.0", "@types/markdown-it": "14.1.2", "@types/markdown-it-container": "2.0.10", "@types/mark.js": "8.11.12", diff --git a/packages/www/src/public/content.json b/packages/www/src/public/content.json index 1611098b..665a7cc9 100644 --- a/packages/www/src/public/content.json +++ b/packages/www/src/public/content.json @@ -96,7 +96,7 @@ { "id": "/api-reference/brisa-cli/brisa-build#build-different-outputs", "title": "Build different outputs", - "text": "If you want to build your application for different outputs, you can use the output field in the brisa.config.ts file. The available outputs are: server: The default output. It generates a server-side application.\nstatic: Generates a static application.\ndesktop: Generates a desktop application.\nandroid: Generates an Android application.\nios: Generates an iOS application. If you want to make a desktop app for Windows, another one for Mac, also android and ios, all at the same time. We recommend you do this in an array inside a pipeline and use an environment variable to decide the output. The good thing is that if you are on Windows, it will use the native Windows stuff for the Destkop app build, the same with Linux and Mac.", + "text": "If you want to build your application for different outputs, you can use the output field in the brisa.config.ts file. The available outputs are: server: The default output. It generates a server-side application.\nstatic: Generates a static application.\ndesktop: Generates a desktop application.\nandroid: Generates an Android application.\nios: Generates an iOS application. If you want to make a desktop app for Windows, another one for Mac, also android and ios, all at the same time. We recommend you do this in an array inside a pipeline and use an environment variable to decide the output. The good thing is that if you are on Windows, it will use the native Windows stuff for the Desktop app build, the same with Linux and Mac.", "titles": [ "Building (brisa build)" ] @@ -129,7 +129,7 @@ { "id": "/api-reference/brisa-cli/brisa-build#ssr-of-web-component", "title": "SSR of Web Component", - "text": "Example server-side rendering these web components in a different JSX framework: import { renderToString } from 'brisa/server';\nimport WebComponent1 from './web-component1.server.ts';\nimport WebComponent2 from './web-component1.server.ts';\n\nconst htmlWC1 = await renderToString();\nconst htmlWC2 = await renderToString(); In the case of incompatibilties with the jsx-runtime, you can use the jsx function: import { renderToString } from 'brisa/server';\nimport { jsx } from 'brisa/jsx-runtime';\nimport WebComponent1 from './web-component1.server.ts';\nimport WebComponent2 from './web-component1.server.ts';\n\nconst htmlWC1 = await renderToString(jsx(WebComponent1, { foo: \"bar\" }));\nconst htmlWC2 = await renderToString(jsx(WebComponent2, { foo: \"bar\" })); The Web Components during SSR are transformed into Declarative Shadow DOM.", + "text": "Example server-side rendering these web components in a different JSX framework: import { renderToString } from 'brisa/server';\nimport WebComponent1 from './web-component1.server.ts';\nimport WebComponent2 from './web-component1.server.ts';\n\nconst htmlWC1 = await renderToString();\nconst htmlWC2 = await renderToString(); In the case of incompatibilities with the jsx-runtime, you can use the jsx function: import { renderToString } from 'brisa/server';\nimport { jsx } from 'brisa/jsx-runtime';\nimport WebComponent1 from './web-component1.server.ts';\nimport WebComponent2 from './web-component1.server.ts';\n\nconst htmlWC1 = await renderToString(jsx(WebComponent1, { foo: \"bar\" }));\nconst htmlWC2 = await renderToString(jsx(WebComponent2, { foo: \"bar\" })); The Web Components during SSR are transformed into Declarative Shadow DOM.", "titles": [ "Building (brisa build)", "Web component build" @@ -146,7 +146,7 @@ { "id": "/api-reference/brisa-cli/brisa-build#how-to-use-the-server-component", "title": "How to use the server component", - "text": "Example using this server component in a different framework: import { renderToString } from 'brisa/server';\nimport { Component } from 'path/component.server.ts';\n\nconst html = await renderToString(); In the case of incompatibilties with the jsx-runtime, you can use the jsx function: import { renderToString } from 'brisa/server';\nimport { jsx } from 'brisa/jsx-runtime';\n\nconst html = await renderToString(jsx(Component, { foo: 'bar' })); Server Actions are not supported in standalone components for security reasons.", + "text": "Example using this server component in a different framework: import { renderToString } from 'brisa/server';\nimport { Component } from 'path/component.server.ts';\n\nconst html = await renderToString(); In the case of incompatibilities with the jsx-runtime, you can use the jsx function: import { renderToString } from 'brisa/server';\nimport { jsx } from 'brisa/jsx-runtime';\n\nconst html = await renderToString(jsx(Component, { foo: 'bar' })); Server Actions are not supported in standalone components for security reasons.", "titles": [ "Building (brisa build)", "Component build" @@ -684,7 +684,7 @@ { "id": "/api-reference/extended-props/indicateEvent#indicateclickindicatorsignal", "title": "indicateClick={IndicatorSignal}", - "text": "Brisa extends all the HTML element events (onInput, onMouseOver, onTouchStart...) to allow to control the pending status of the server action by replacing the on prefix to indicate. The value is the generated IndicatorSignal by the indicate method: Read more docs about indicate in Server Components.\nRead more docs about indicate in Web Components. const indicator = indicate('some-action-name')\n// ...\n console.log(e.target.value)}\n indicateInput={indicator} // IndicatorSignal\n debouceInput={300}\n/> In this example, we are registering the indicator in the onClick server action through the indicate[Event] attribute.", + "text": "Brisa extends all the HTML element events (onInput, onMouseOver, onTouchStart...) to allow to control the pending status of the server action by replacing the on prefix to indicate. The value is the generated IndicatorSignal by the indicate method: Read more docs about indicate in Server Components.\nRead more docs about indicate in Web Components. const indicator = indicate('some-action-name')\n// ...\n console.log(e.target.value)}\n indicateInput={indicator} // IndicatorSignal\n debounceInput={300}\n/> In this example, we are registering the indicator in the onClick server action through the indicate[Event] attribute.", "titles": [ "indicate[Event]", "Reference" @@ -693,7 +693,7 @@ { "id": "/api-reference/extended-props/indicateEvent#parameters", "title": "Parameters:", - "text": "IndicatorSignal - Indicator signal generared by indicate method. This indicate[Event] attribute is only implemented in server components, because the server actions are only in server components.", + "text": "IndicatorSignal - Indicator signal generated by indicate method. This indicate[Event] attribute is only implemented in server components, because the server actions are only in server components.", "titles": [ "indicate[Event]", "Reference", @@ -744,7 +744,7 @@ { "id": "/api-reference/extended-props/indicator#parameters", "title": "Parameters:", - "text": "IndicatorSignal | IndicatorSignal[] - One or several IndicatorSignal generared by indicate method.", + "text": "IndicatorSignal | IndicatorSignal[] - One or several IndicatorSignal generated by indicate method.", "titles": [ "indicator", "Reference", @@ -850,7 +850,7 @@ { "id": "/api-reference/extended-props/renderMode#rendermodereactivity-or-transition-or-native", "title": "renderMode={'reactivity' | 'transition' | 'native'}", - "text": "The renderMode attribute is present on the element to specify the render mode of the next document after following the link. There are three possible values: reactivity: The next document will be rendered using reactivity. It only changes the parts of the page that have changed, perserving Web Component states.\ntransition: The next document will be rendered using reactivity and also using View Transition API.\nnative: The next document will be rendered using the browser's native rendering engine. By default, the value is reactivity. Note: If the origin of the next document is different from the current document, the value will be ignored, and the next document will be rendered using the browser's native rendering engine. Example: return ;", + "text": "The renderMode attribute is present on the element to specify the render mode of the next document after following the link. There are three possible values: reactivity: The next document will be rendered using reactivity. It only changes the parts of the page that have changed, preserving Web Component states.\ntransition: The next document will be rendered using reactivity and also using View Transition API.\nnative: The next document will be rendered using the browser's native rendering engine. By default, the value is reactivity. Note: If the origin of the next document is different from the current document, the value will be ignored, and the next document will be rendered using the browser's native rendering engine. Example: return ;", "titles": [ "renderMode", "Reference" @@ -1102,7 +1102,7 @@ { "id": "/api-reference/functions/navigate#navigateroute-string-options-rendermode-transition-or-reactivity-or-native-never", "title": "navigate(route: string, options?: { renderMode?: 'transition' | 'reactivity' | 'native' }): never", - "text": "The navigate function is used for imperative navigation. import { navigate } from \"brisa\";\n\n// ...\nnavigate(\"/some-page\"); The navigate function can be used both on the client and on the server. Although there are some differences to be taken into account: If the navigation is done before sending the response (in the middleware, responseHeaders or an API endpoint for example), instead of modifying the navigation history it does a 301 redirect.\nIf it is done during rendering, SPA navigation or Server Action a soft redirect is made.\nIf used inside a client-event or a server-event (action) a new page is always generated in the navigation history. All i18n navigaton rules apply equally in this function.", + "text": "The navigate function is used for imperative navigation. import { navigate } from \"brisa\";\n\n// ...\nnavigate(\"/some-page\"); The navigate function can be used both on the client and on the server. Although there are some differences to be taken into account: If the navigation is done before sending the response (in the middleware, responseHeaders or an API endpoint for example), instead of modifying the navigation history it does a 301 redirect.\nIf it is done during rendering, SPA navigation or Server Action a soft redirect is made.\nIf used inside a client-event or a server-event (action) a new page is always generated in the navigation history. All i18n navigation rules apply equally in this function.", "titles": [ "navigate", "Reference" @@ -2244,7 +2244,7 @@ { "id": "/building-your-application/building/desktop-app#brisa-desktop-applications-tauri-integration", "title": "Brisa Desktop Applications (Tauri integration)", - "text": "This documentation outlines the process of building a Brisa desktop application using Tauri. Tauri is seamlessly integrated into Brisa by configuring the brisa.config.ts file as follows: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"desktop\",\n} satisfies Configuration; Prerequisits: you need to have cargo installed. To initialize the development environment, run the following command: brisa dev Executing this command launches a desktop app, integrating your web application. The development environment supports hot-reloading, mirroring the behavior of a browser. Notably, the integration creates a src-tauri folder, representing the fusion of Brisa with Tauri. Customizing the window size, icons, title, and other attributes can be achieved by modifying the src-tauri/tauri.conf.json file. Explore Tauri's configuration fields here.", + "text": "This documentation outlines the process of building a Brisa desktop application using Tauri. Tauri is seamlessly integrated into Brisa by configuring the brisa.config.ts file as follows: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"desktop\",\n} satisfies Configuration; Prerequisites: you need to have cargo installed. To initialize the development environment, run the following command: brisa dev Executing this command launches a desktop app, integrating your web application. The development environment supports hot-reloading, mirroring the behavior of a browser. Notably, the integration creates a src-tauri folder, representing the fusion of Brisa with Tauri. Customizing the window size, icons, title, and other attributes can be achieved by modifying the src-tauri/tauri.conf.json file. Explore Tauri's configuration fields here.", "titles": [ "Desktop app" ] @@ -2275,7 +2275,7 @@ { "id": "/building-your-application/building/ios-app#brisa-ios-applications-tauri-integration", "title": "Brisa iOS Applications (Tauri integration)", - "text": "This documentation outlines the process of building a Brisa ios application using Tauri. Tauri is seamlessly integrated into Brisa by configuring the brisa.config.ts file as follows: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"ios\",\n} satisfies Configuration; To initialize the development environment, run the following command: brisa dev Prerequisits:\n\nYou need to have cargo installed.\nYou need to download iOS targets and follow these steps from Tauri documentation. Executing this command launches a ios app, integrating your web application. The development environment supports hot-reloading, mirroring the behavior of a browser. Notably, the integration creates a src-tauri folder, representing the fusion of Brisa with Tauri. Customizing the icons, title, and other attributes can be achieved by modifying the src-tauri/tauri.conf.json file. Explore Tauri's configuration fields here.", + "text": "This documentation outlines the process of building a Brisa ios application using Tauri. Tauri is seamlessly integrated into Brisa by configuring the brisa.config.ts file as follows: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"ios\",\n} satisfies Configuration; To initialize the development environment, run the following command: brisa dev Prerequisites:\n\nYou need to have cargo installed.\nYou need to download iOS targets and follow these steps from Tauri documentation. Executing this command launches a ios app, integrating your web application. The development environment supports hot-reloading, mirroring the behavior of a browser. Notably, the integration creates a src-tauri folder, representing the fusion of Brisa with Tauri. Customizing the icons, title, and other attributes can be achieved by modifying the src-tauri/tauri.conf.json file. Explore Tauri's configuration fields here.", "titles": [ "iOS app" ] @@ -2617,8 +2617,8 @@ ] }, { - "id": "/building-your-application/components-details/forms#web-component-not-recomended", - "title": "Web component (not recomended 👎)", + "id": "/building-your-application/components-details/forms#web-component-not-recommended", + "title": "Web component (not recommended 👎)", "text": "The client code of a uncontrolled form would be as follows: export default function UncontrolledFormClient() {\n return (\n {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n console.log(\"Username:\", formData.get(\"username\"));\n }}\n >\n \n
\n \n \n );\n} If you are making an uncontrolled form in a web component it is a sign that you are writing code on the client that could be written on the server. Use only uncontrolled form in web components only if you don't need to make a request to the server after the submit. Otherwise use a server component. Using uncontrolled form in web components adds client JS code, not only the event JS, but also the JS of the web component itself.", "titles": [ "Forms", @@ -2626,8 +2626,8 @@ ] }, { - "id": "/building-your-application/components-details/forms#controlled-forms-not-recomended", - "title": "Controlled Forms (not recomended 👎)", + "id": "/building-your-application/components-details/forms#controlled-forms-not-recommended", + "title": "Controlled Forms (not recommended 👎)", "text": "A controlled form in Brisa is a form whose state is controlled by the Brisa web component. In other words, the form elements such as input fields, checkbox, radio buttons, etc have their values bound to the component's state. This allows to manage and control the form's behavior and be able to give instant feedback to the user about errors. Despite the benefits of controlled forms, it's important to note that Brisa doesn't necessarily recommend their use in all scenarios. The decision to opt for controlled or uncontrolled forms should be driven by specific requirements and architectural considerations. In certain cases, controlled forms may introduce unnecessary complexity, especially when dealing with large forms or integrating with external libraries. Developers should carefully assess the trade-offs and choose the approach that aligns best with their application's needs. import { type WebContext } from \"brisa\";\n\nexport default function ControlledFormExample({}, { state }: WebContext) {\n const username = state(\"\");\n\n return (\n {\n e.preventDefault();\n console.log(\"Username:\", username.value);\n }}\n >\n \n
\n \n \n );\n} If you want to use controlled forms, we recommend that you use it in the web components and not in the server components. If you want to manage the onSubmit for the server, you can manage it through a prop and the parent server component capture and handle the event. import { type WebContext } from \"brisa\";\n\n// Web component:\nexport default function ControlledFormExample(\n { onFormSubmit }, // Event captured and handled by server component\n { state }: WebContext,\n) {\n const username = state(\"\");\n\n return (\n
onFormSubmit({ username })}>\n \n
\n \n
\n );\n} And: // Server component:\nexport default function Page() {\n const onFormSubmit = ({ username }) => {\n // This event is handled in the server, we can save it to the DB.\n };\n\n return ;\n} Controlled forms introduce additional complexity and more client-side JavaScript code. Developers should carefully weigh these factors when choosing between controlled and uncontrolled forms. The Brisa team recommends using controlled forms primarily when providing instant feedback to users for each modification during form interactions. Otherwise, it is advisable to opt for uncontrolled forms with a server component.", "titles": [ "Forms" @@ -2692,7 +2692,7 @@ { "id": "/building-your-application/components-details/reactivity#can-i-use-signals-in-the-server", "title": "Can I use signals in the server?", - "text": "No directly. The signals are reactive and they are used in the client-side. However, action-signals concept exists and you can use the server store method and transfer some store fields to the client-side and reactively update them on a server action. import type { RequestContext } from \"brisa\";\nimport { renderPage } from \"brisa/server\";\n\nexport default function ServerComponent({}, { store }: RequestContext) {\n // Setting store\n if (!store.has(\"user\")) {\n store.set(\"user\", { username: \"foo\", displayName: \"Foo\" });\n }\n\n // Extends the life of the store property beyond request-time\n // (Necessary to use it in a server action)\n store.transferToClient([\"user\"]);\n\n function updateName() {\n // Update the store inside a server action\n store.set(\"user\", { username: \"bar\", displayName: \"Bar\" });\n renderPage();\n }\n\n // Consuming store\n return (\n <>\n Hello {store.get(\"user\").displayName}\n \n \n );\n} The natural lifecycle of the server store is: Middleware\nRendering (layout, page, components) But thanks to store.transferToClient method, you extend the lifecycle of some store fields to: Middleware\nRendering (layout, page, components)\nClient side (as signal)\nServer Actions\nClient side (as signal)\netc ... And modifing the value on server actions, is reflected in a reactive way on the client side signals.", + "text": "No directly. The signals are reactive and they are used in the client-side. However, action-signals concept exists and you can use the server store method and transfer some store fields to the client-side and reactively update them on a server action. import type { RequestContext } from \"brisa\";\nimport { renderPage } from \"brisa/server\";\n\nexport default function ServerComponent({}, { store }: RequestContext) {\n // Setting store\n if (!store.has(\"user\")) {\n store.set(\"user\", { username: \"foo\", displayName: \"Foo\" });\n }\n\n // Extends the life of the store property beyond request-time\n // (Necessary to use it in a server action)\n store.transferToClient([\"user\"]);\n\n function updateName() {\n // Update the store inside a server action\n store.set(\"user\", { username: \"bar\", displayName: \"Bar\" });\n renderPage();\n }\n\n // Consuming store\n return (\n <>\n Hello {store.get(\"user\").displayName}\n \n \n );\n} The natural lifecycle of the server store is: Middleware\nRendering (layout, page, components) But thanks to store.transferToClient method, you extend the lifecycle of some store fields to: Middleware\nRendering (layout, page, components)\nClient side (as signal)\nServer Actions\nClient side (as signal)\netc ... And modifying the value on server actions, is reflected in a reactive way on the client side signals.", "titles": [ "Reactivity" ] @@ -2879,7 +2879,7 @@ { "id": "/building-your-application/components-details/web-components#props", "title": "Props", - "text": "Brisa components use props to communicate with each other. Every parent component can pass some information to its child components by giving them props. Props might remind you of HTML attributes, but you can pass any JavaScript value through them, including objects, arrays, and functions. The properties are signals but can be used directly without using the .value, because they are readonly. Good to know: Since props are signals, consume them directly or use derived method. Doing so breaks the reactivity:\nexport default function UserImages({ urls }, { derived }) {\n // ❌ variable is no longer reactive\n const firstImage = urls[0];\n // ✅ Instead, use derived:\n const reactiveFirstImage = derived(() => urls[0]);\n}\n\nIn Brisa we are doing optimizations in build-time to avoid losing the reactivity of the props declared on the parameters. So the last example can be solved without the derived method with these props declaration:\nexport default function UserImages({ urls: [firstImage] }) {\n // firstImage is reactive\n}\n\nHowever, it is important to know that if you declare a variable with the prop, it will not be reactive. Avoid spreading props without specify the prop field:\nexport default function UserImages(props) {\n // ❌ Brisa can't know what is the prop field to observe\n return ;\n}\n\nThis is not related with reacitivity, but for web components Brisa needs to specify the observedAttributes.", + "text": "Brisa components use props to communicate with each other. Every parent component can pass some information to its child components by giving them props. Props might remind you of HTML attributes, but you can pass any JavaScript value through them, including objects, arrays, and functions. The properties are signals but can be used directly without using the .value, because they are readonly. Good to know: Since props are signals, consume them directly or use derived method. Doing so breaks the reactivity:\nexport default function UserImages({ urls }, { derived }) {\n // ❌ variable is no longer reactive\n const firstImage = urls[0];\n // ✅ Instead, use derived:\n const reactiveFirstImage = derived(() => urls[0]);\n}\n\nIn Brisa we are doing optimizations in build-time to avoid losing the reactivity of the props declared on the parameters. So the last example can be solved without the derived method with these props declaration:\nexport default function UserImages({ urls: [firstImage] }) {\n // firstImage is reactive\n}\n\nHowever, it is important to know that if you declare a variable with the prop, it will not be reactive. Avoid spreading props without specify the prop field:\nexport default function UserImages(props) {\n // ❌ Brisa can't know what is the prop field to observe\n return ;\n}\n\nThis is not related with reactivity, but for web components Brisa needs to specify the observedAttributes.", "titles": [ "Web Components" ] @@ -3665,7 +3665,7 @@ { "id": "/building-your-application/configuring/output#5-android-output-android", "title": "5. Android Output (android)", - "text": "The android output type is designed for creating deployable android applications, integrated with Tauri. To set up your Brisa project for desktop output, modify your brisa.config.ts as shown below: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"android\",\n} satisfies Configuration; Prerequisits: You need to download Android Studio and follow these steps from Tauri documentation. Once activated you can call brisa dev to work locally with hotreloading in the android app or brisa build to build the android app native executables. You can do brisa dev --skip-tauri or brisa build --skip-tauri if you want to avoid creating and loading the android application. In production the build is done as static export, since there is no server.\nPure server stuff like api endpoints and server interactions will not work in runtime. All the interaction part should be in web-components only. Lean how to build a android app here.", + "text": "The android output type is designed for creating deployable android applications, integrated with Tauri. To set up your Brisa project for desktop output, modify your brisa.config.ts as shown below: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"android\",\n} satisfies Configuration; Prerequisites: You need to download Android Studio and follow these steps from Tauri documentation. Once activated you can call brisa dev to work locally with hotreloading in the android app or brisa build to build the android app native executables. You can do brisa dev --skip-tauri or brisa build --skip-tauri if you want to avoid creating and loading the android application. In production the build is done as static export, since there is no server.\nPure server stuff like api endpoints and server interactions will not work in runtime. All the interaction part should be in web-components only. Lean how to build a android app here.", "titles": [ "Output", "Understanding Output Types" @@ -3674,7 +3674,7 @@ { "id": "/building-your-application/configuring/output#6-ios-output-ios", "title": "6. iOS Output (ios)", - "text": "The ios output type is designed for creating deployable iOS applications, integrated with Tauri. To set up your Brisa project for desktop output, modify your brisa.config.ts as shown below: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"ios\",\n} satisfies Configuration; Prerequisits: You need to download iOS targets and follow these steps from Tauri documentation. Once activated you can call brisa dev to work locally with hotreloading in the iOS app or brisa build to build the iOS app native executables. You can do brisa dev --skip-tauri or brisa build --skip-tauri if you want to avoid creating and loading the iOS application. In production the build is done as static export, since there is no server.\nPure server stuff like api endpoints and server interactions will not work in runtime. All the interaction part should be in web-components only. Lean how to build a iOS app here.", + "text": "The ios output type is designed for creating deployable iOS applications, integrated with Tauri. To set up your Brisa project for desktop output, modify your brisa.config.ts as shown below: import type { Configuration } from \"brisa\";\n\nexport default {\n output: \"ios\",\n} satisfies Configuration; Prerequisites: You need to download iOS targets and follow these steps from Tauri documentation. Once activated you can call brisa dev to work locally with hotreloading in the iOS app or brisa build to build the iOS app native executables. You can do brisa dev --skip-tauri or brisa build --skip-tauri if you want to avoid creating and loading the iOS application. In production the build is done as static export, since there is no server.\nPure server stuff like api endpoints and server interactions will not work in runtime. All the interaction part should be in web-components only. Lean how to build a iOS app here.", "titles": [ "Output", "Understanding Output Types" @@ -3744,7 +3744,7 @@ { "id": "/building-your-application/configuring/static-pages#prerender-some-pages-in-outputbun-or-outputnode", "title": "Prerender some pages in output=\"bun\" or output=\"node\"", - "text": "In Brisa you can prerender pages to have a static/dynamic hybrid app. Although in the configuration is a JS Server you can indicate which pages you want to prerender during the build and then only have to serve the generated HTML file. For this to be possible, you have to put prerender named export on your pages: export const prerender = true;\n\nexport default function MyPage() {\n // ...\n} The prerender export can be a boolean or a () => {[param: string]: string|string[]}[] | async () => {[param: string]: string|string[]}[] (only in the case of dynamic routes to indicate all the necesary params to prerender). In the case of a page that is not [dynamic], [[...catchAll]], or [...rest], the boolean is enough. The boolean only applies when the [`output` is a JS Server (`bun` | node`)](/building-your-application/configuring/output), for the other `output` types all pages will automatically be pre-rendered since there will be no server.", + "text": "In Brisa you can prerender pages to have a static/dynamic hybrid app. Although in the configuration is a JS Server you can indicate which pages you want to prerender during the build and then only have to serve the generated HTML file. For this to be possible, you have to put prerender named export on your pages: export const prerender = true;\n\nexport default function MyPage() {\n // ...\n} The prerender export can be a boolean or a () => {[param: string]: string|string[]}[] | async () => {[param: string]: string|string[]}[] (only in the case of dynamic routes to indicate all the necessary params to prerender). In the case of a page that is not [dynamic], [[...catchAll]], or [...rest], the boolean is enough. The boolean only applies when the [`output` is a JS Server (`bun` | node`)](/building-your-application/configuring/output), for the other `output` types all pages will automatically be pre-rendered since there will be no server.", "titles": [ "Static pages" ] @@ -3784,7 +3784,7 @@ { "id": "/building-your-application/configuring/tls#tls", "title": "TLS", - "text": "Brisa supports TLS out of the box thanks to Bun, powered by BoringSSL. Enable TLS by passing in a value for key and cert; both are required to enable TLS. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"),\n cert: Bun.file(\"./cert.pem\"),\n },\n} satisfies Configuration; The key and cert fields expect the contents of your TLS key and certificate, not a path to it. This can be a string, BunFile, TypedArray, or Buffer. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n // BunFile\n key: Bun.file(\"./key.pem\"),\n // Buffer\n key: fs.readFileSync(\"./key.pem\"),\n // string\n key: fs.readFileSync(\"./key.pem\", \"utf8\"),\n // array of above\n key: [Bun.file(\"./key1.pem\"), Bun.file(\"./key2.pem\")],\n },\n} satisfies Configuration; If your private key is encrypted with a passphrase, provide a value for passphrase to decrypt it. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"),\n cert: Bun.file(\"./cert.pem\"),\n passphrase: \"my-secret-passphrase\",\n },\n} satisfies Configuration; Optionally, you can override the trusted CA certificates by passing a value for ca. By default, the server will trust the list of well-known CAs curated by Mozilla. When ca is specified, the Mozilla list is overwritten. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"), // path to TLS key\n cert: Bun.file(\"./cert.pem\"), // path to TLS cert\n ca: Bun.file(\"./ca.pem\"), // path to root CA certificate\n },\n} satisfies Configuration; To override Diffie-Helman parameters: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n // other config\n dhParamsFile: \"/path/to/dhparams.pem\", // path to Diffie Helman parameters\n },\n} satisfies Configuration;", + "text": "Brisa supports TLS out of the box thanks to Bun, powered by BoringSSL. Enable TLS by passing in a value for key and cert; both are required to enable TLS. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"),\n cert: Bun.file(\"./cert.pem\"),\n },\n} satisfies Configuration; The key and cert fields expect the contents of your TLS key and certificate, not a path to it. This can be a string, BunFile, TypedArray, or Buffer. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n // BunFile\n key: Bun.file(\"./key.pem\"),\n // Buffer\n key: fs.readFileSync(\"./key.pem\"),\n // string\n key: fs.readFileSync(\"./key.pem\", \"utf8\"),\n // array of above\n key: [Bun.file(\"./key1.pem\"), Bun.file(\"./key2.pem\")],\n },\n} satisfies Configuration; If your private key is encrypted with a passphrase, provide a value for passphrase to decrypt it. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"),\n cert: Bun.file(\"./cert.pem\"),\n passphrase: \"my-secret-passphrase\",\n },\n} satisfies Configuration; Optionally, you can override the trusted CA certificates by passing a value for ca. By default, the server will trust the list of well-known CAs curated by Mozilla. When ca is specified, the Mozilla list is overwritten. brisa.config.ts: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n key: Bun.file(\"./key.pem\"), // path to TLS key\n cert: Bun.file(\"./cert.pem\"), // path to TLS cert\n ca: Bun.file(\"./ca.pem\"), // path to root CA certificate\n },\n} satisfies Configuration; To override Diffie-Hellman parameters: import type { Configuration } from \"brisa\";\n\nexport default {\n tls: {\n // other config\n dhParamsFile: \"/path/to/dhparams.pem\", // path to Diffie Hellman parameters\n },\n} satisfies Configuration;", "titles": [] }, { @@ -3910,7 +3910,7 @@ { "id": "/building-your-application/data-management/fetching#share-server-server-data-between-components", "title": "Share server-server data between components", - "text": "To share data across all parts of the server (middleware, layout, responseHeaders, Head, suspense phase, etc) there are two ways: Request store\nContext API Example using store: import { type RequestContext } from \"brisa\";\n\ntype Props = {};\n\nexport async function Main({}: Props, request: RequestContext) {\n const res = await fetch(/* */);\n const user = await res.json();\n\n // Set key-value data to request store\n request.store.set(\"user\", user);\n\n return ;\n}\n\nMain.suspense = ({}: Props, request: RequestContext) => (\n
Loading user...
\n);\n\nexport function UserInfo({}: Props, request: RequestContext) {\n const user = request.store.get(\"user\");\n\n return
Hello {user.name}
;\n} Example using Context API: import { type RequestContext, createStore } from \"brisa\";\n\ntype Props = {};\n\nconst UserCtx = createStore();\n\nexport async function Main({}: Props, request: RequestContext) {\n const res = await fetch(/* */);\n const user = await res.json();\n\n // Use serverOnly inside context-provider to avoid to create a web\n // component for the provider and share the data only with the\n // server part\n return (\n \n \n \n );\n}\n\nMain.suspense = ({}: Props, request: RequestContext) => (\n
Loading user...
\n);\n\nexport function UserInfo({}: Props, request: RequestContext) {\n const user = request.useContext(UserCtx);\n\n return
Hello {user.value.name}
;\n} We recommend that whenever possible you add the data to the store inside the request. And use the Context API only in specific cases where you only want to share this data with a piece of the component tree. The reason is that the Context API is more expensive and if you don't put the serverOnly attribute it creates a DOM element (context-provider) and shares the data with the rest of the web-components that are in the same component tree. In both cases the data lives within the lifetime of the request, it is not global data, and one of the benefits is that all server-components receive the RequestContext as a second parameter, and you can access easly to that data. The RequestContext is an extension of the Request, where apart from the Request API you have some extra things, such as the store. If your data is utilized in multiple locations, and you wish to display the suspense at the lowest-level component while making only one request, we recommend passing down the promise and resolving it in all child components that utilize this data.", + "text": "To share data across all parts of the server (middleware, layout, responseHeaders, Head, suspense phase, etc) there are two ways: Request store\nContext API Example using store: import { type RequestContext } from \"brisa\";\n\ntype Props = {};\n\nexport async function Main({}: Props, request: RequestContext) {\n const res = await fetch(/* */);\n const user = await res.json();\n\n // Set key-value data to request store\n request.store.set(\"user\", user);\n\n return ;\n}\n\nMain.suspense = ({}: Props, request: RequestContext) => (\n
Loading user...
\n);\n\nexport function UserInfo({}: Props, request: RequestContext) {\n const user = request.store.get(\"user\");\n\n return
Hello {user.name}
;\n} Example using Context API: import { type RequestContext, createStore } from \"brisa\";\n\ntype Props = {};\n\nconst UserCtx = createStore();\n\nexport async function Main({}: Props, request: RequestContext) {\n const res = await fetch(/* */);\n const user = await res.json();\n\n // Use serverOnly inside context-provider to avoid to create a web\n // component for the provider and share the data only with the\n // server part\n return (\n \n \n \n );\n}\n\nMain.suspense = ({}: Props, request: RequestContext) => (\n
Loading user...
\n);\n\nexport function UserInfo({}: Props, request: RequestContext) {\n const user = request.useContext(UserCtx);\n\n return
Hello {user.value.name}
;\n} We recommend that whenever possible you add the data to the store inside the request. And use the Context API only in specific cases where you only want to share this data with a piece of the component tree. The reason is that the Context API is more expensive and if you don't put the serverOnly attribute it creates a DOM element (context-provider) and shares the data with the rest of the web-components that are in the same component tree. In both cases the data lives within the lifetime of the request, it is not global data, and one of the benefits is that all server-components receive the RequestContext as a second parameter, and you can access easily to that data. The RequestContext is an extension of the Request, where apart from the Request API you have some extra things, such as the store. If your data is utilized in multiple locations, and you wish to display the suspense at the lowest-level component while making only one request, we recommend passing down the promise and resolving it in all child components that utilize this data.", "titles": [ "Data Fetching" ] @@ -4126,7 +4126,7 @@ { "id": "/building-your-application/data-management/server-actions#using-data-attributes", "title": "Using data attributes", - "text": "You can use data- attributes to transfer data from the client to the server. This is useful when you need to send data that is not in a form. {\n // All this code runs only on the server\n const value = e.target.value;\n\n // Get the value in the server action\n const id = e.target.dataset.id;\n }}\n data-id=\"123\"\n/> You also can encrypt / decrypt sensivle data using data-attributes: import { encrypt, decrypt } from \"brisa/server\";\n\n// ...\n {\n // Decrypt on the server action:\n console.log(\n decrypt((e.target as HTMLButtonElement).dataset.encrypted!)\n )\n }}\n data-encrypted={encrypt(\"some sensible data\")}\n>\n Click to recover sensible data on the server\n", + "text": "You can use data- attributes to transfer data from the client to the server. This is useful when you need to send data that is not in a form. {\n // All this code runs only on the server\n const value = e.target.value;\n\n // Get the value in the server action\n const id = e.target.dataset.id;\n }}\n data-id=\"123\"\n/> You also can encrypt / decrypt sensitive data using data-attributes: import { encrypt, decrypt } from \"brisa/server\";\n\n// ...\n {\n // Decrypt on the server action:\n console.log(\n decrypt((e.target as HTMLButtonElement).dataset.encrypted!)\n )\n }}\n data-encrypted={encrypt(\"some sensible data\")}\n>\n Click to recover sensible data on the server\n", "titles": [ "Server Actions", "Transfer data" @@ -4288,7 +4288,7 @@ { "id": "/building-your-application/deploying/docker#containerize-with-docker", "title": "Containerize with Docker", - "text": "This guide assumes you already have Docker Desktop installed. Docker is a platform for packaging and running an application as a lightweight, portable container that encapsulates all the necessary dependencies. To containerize our application, we define a Dockerfile. This file contains a list of instructions to initialize the container, copy our local project files into it, install dependencies, and start the application. # Adjust BUN_VERSION as desired\nARG BUN_VERSION=1.1.42\nFROM oven/bun:${BUN_VERSION}-slim AS base\n\n# Brisa app lives here\nWORKDIR /app\n\n# Set production environment\nENV NODE_ENV=\"production\"\n\n# Throw-away build stage to reduce the size of the final image\nFROM base AS build\n\n# Install node modules\nCOPY --link bun.lockb package.json ./\nRUN bun install --ci\n\n# Copy Brisa application code\nCOPY --link . .\n\n# Build Brisa application\nRUN bun run build\n\n# Final stage for app image\nFROM base\n\n# Copy built Brisa application\nCOPY --from=build /app /app\n\n# Start the Brisa server on port 3000\nEXPOSE 3000\nCMD [ \"bun\", \"run\", \"start\" ] Now that you have your docker image, let's look at .dockerignore which has the same syntax as .gitignore; here, you need to specify the files/directories that must not go in any stage of the docker build. An example of a ignore file is: dockerignore: .vscode\nnode_modules\n.DS_Store\nbuild If you want to be more strict, you can also invert the .dockerignore and use it as an allowed file. An example of how this would work is: dockerignore: # Ignore all files from your repo\n*\n\n# Allow specific files or folders\n!bun.lockb\n!package.json\n!src Making the .dockerignore an allowed file becomes very handy to prevent trash on your image, or sensitive information. For example secrets, coverage files or another dev on your team using a different IDE. We'll now use docker build to convert this Dockerfile into a Docker image. The result will be a self-contained template containing all the dependencies and configurations required to run the application on any platform. docker build -t my-app . The -t flag lets us specify a name for the image. We've built a new Docker image. Now let's use that image to spin up an actual, running container. docker run -p 3000:3000 my-app We'll use docker run to start a new container using the my-app image. We'll map the container's port 3000 to our local machine's port 3000 (-p 3000:3000). The run command prints a string representing the container ID. The container is now running in the background. Visit localhost:3000. You should see your homepage. Optional: the flag -d flag to run in detached mode to run the container in the background. To stop the container, we'll use docker stop . If you can't find the container ID, you can use docker ps to list all running containers. That's it! Refer to the Docker documentation for more advanced usage.", + "text": "This guide assumes you already have Docker Desktop installed. Docker is a platform for packaging and running an application as a lightweight, portable container that encapsulates all the necessary dependencies. To containerize our application, we define a Dockerfile. This file contains a list of instructions to initialize the container, copy our local project files into it, install dependencies, and start the application. # Adjust BUN_VERSION as desired\nARG BUN_VERSION=1.2.0\nFROM oven/bun:${BUN_VERSION}-slim AS base\n\n# Brisa app lives here\nWORKDIR /app\n\n# Set production environment\nENV NODE_ENV=\"production\"\n\n# Throw-away build stage to reduce the size of the final image\nFROM base AS build\n\n# Install node modules\nCOPY --link bun.lockb package.json ./\nRUN bun install --ci\n\n# Copy Brisa application code\nCOPY --link . .\n\n# Build Brisa application\nRUN bun run build\n\n# Final stage for app image\nFROM base\n\n# Copy built Brisa application\nCOPY --from=build /app /app\n\n# Start the Brisa server on port 3000\nEXPOSE 3000\nCMD [ \"bun\", \"run\", \"start\" ] Now that you have your docker image, let's look at .dockerignore which has the same syntax as .gitignore; here, you need to specify the files/directories that must not go in any stage of the docker build. An example of a ignore file is: dockerignore: .vscode\nnode_modules\n.DS_Store\nbuild If you want to be more strict, you can also invert the .dockerignore and use it as an allowed file. An example of how this would work is: dockerignore: # Ignore all files from your repo\n*\n\n# Allow specific files or folders\n!bun.lockb\n!package.json\n!src Making the .dockerignore an allowed file becomes very handy to prevent trash on your image, or sensitive information. For example secrets, coverage files or another dev on your team using a different IDE. We'll now use docker build to convert this Dockerfile into a Docker image. The result will be a self-contained template containing all the dependencies and configurations required to run the application on any platform. docker build -t my-app . The -t flag lets us specify a name for the image. We've built a new Docker image. Now let's use that image to spin up an actual, running container. docker run -p 3000:3000 my-app We'll use docker run to start a new container using the my-app image. We'll map the container's port 3000 to our local machine's port 3000 (-p 3000:3000). The run command prints a string representing the container ID. The container is now running in the background. Visit localhost:3000. You should see your homepage. Optional: the flag -d flag to run in detached mode to run the container in the background. To stop the container, we'll use docker stop . If you can't find the container ID, you can use docker ps to list all running containers. That's it! Refer to the Docker documentation for more advanced usage.", "titles": [ "Docker" ] @@ -4325,8 +4325,8 @@ "titles": [] }, { - "id": "/building-your-application/deploying/fly-io#requeriments", - "title": "Requeriments", + "id": "/building-your-application/deploying/fly-io#requirements", + "title": "Requirements", "text": "Follow this docs to install flyctl: https://fly.io/docs/hands-on/install-flyctl/ Then, login with: flyctl auth login", "titles": [ "Deploying to Fly.io" @@ -4343,7 +4343,7 @@ { "id": "/building-your-application/deploying/render-com#deploying-on-rendercom", "title": "Deploying on Render.com", - "text": "This documentation outlines the process of deploying a Brisa application on Render.com. Render is a cloud service provider that offers uploaddable static sites and a web service with docker containers. Depending on your output strategy, you can deploy your Brisa application on Render.com using different approaches: Static Sites (output=\"static\"): You can deploy your Brisa application as a static website on Render.com.\nWeb Services (output=\"bun\" | output=\"node\"): You can containerize your Brisa application using Docker and deploy it on Render.com.", + "text": "This documentation outlines the process of deploying a Brisa application on Render.com. Render is a cloud service provider that offers uploadable static sites and a web service with docker containers. Depending on your output strategy, you can deploy your Brisa application on Render.com using different approaches: Static Sites (output=\"static\"): You can deploy your Brisa application as a static website on Render.com.\nWeb Services (output=\"bun\" | output=\"node\"): You can containerize your Brisa application using Docker and deploy it on Render.com.", "titles": [] }, { @@ -4501,11 +4501,29 @@ { "id": "/building-your-application/integrations/tailwind-css#installation", "title": "Installation", - "text": "Run this command to integrate TailwindCSS in your Brisa project: bunx brisa add tailwindcss And you are ready to use TailwindCSS in your Brisa project.", + "text": "Follow these steps to set up TailwindCSS in your Brisa project:", "titles": [ "Integrating Tailwind CSS v4" ] }, + { + "id": "/building-your-application/integrations/tailwind-css#1-install-tailwindcss", + "title": "1. Install TailwindCSS", + "text": "Run the following command to add TailwindCSS to your project: bunx brisa add tailwindcss", + "titles": [ + "Integrating Tailwind CSS v4", + "Installation" + ] + }, + { + "id": "/building-your-application/integrations/tailwind-css#2-import-tailwindcss", + "title": "2. Import TailwindCSS", + "text": "After the installation, import TailwindCSS in your main CSS file: @import \"tailwindcss\"; Then, import this CSS file in src/layout/index.tsx. And that's it! You're all set to use TailwindCSS in your Brisa project.", + "titles": [ + "Integrating Tailwind CSS v4", + "Installation" + ] + }, { "id": "/building-your-application/integrations/tailwind-css#manual-installation", "title": "Manual Installation", @@ -4934,8 +4952,8 @@ ] }, { - "id": "/building-your-application/routing/internationalization#default-value-when-translation-doest-exist", - "title": "Default value when translation does't exist", + "id": "/building-your-application/routing/internationalization#default-value-when-translation-doesnt-exist", + "title": "Default value when translation doesn't exist", "text": "If the translation does not exist and all fallback keys fail (if any), then as default behavior, the key is shown. t(\"hello\", { name: \"Brisa\" }); // Hello Brisa\nt(\"no-existing-key\"); // no-existing-key", "titles": [ "Internationalization (i18n)", @@ -4949,7 +4967,7 @@ "titles": [ "Internationalization (i18n)", "Consume translations", - "Default value when translation does't exist" + "Default value when translation doesn't exist" ] }, { @@ -5129,7 +5147,7 @@ { "id": "/building-your-application/routing/linking-and-navigating#navigate-function", "title": "navigate function", - "text": "The navigate function is used for imperative navigation. import { navigate } from \"brisa\";\n\n// ...\nnavigate(\"/some-page\"); The navigate function can be used both on the client and on the server. Although there are some differences to be taken into account: If the navigation is done before sending the response (in the middleware, responseHeaders or an API endpoint for example), instead of modifying the navigation history it does a 301 redirect.\nIf it is done during rendering, SPA navigation or Server Action a soft redirect is made.\nIf used inside a client-event or a server-event (action) a new page is always generated in the navigation history. All i18n navigaton rules apply equally in this function. navigate('/some') does not require you to use return navigate('/some') due to using the TypeScript never type.", + "text": "The navigate function is used for imperative navigation. import { navigate } from \"brisa\";\n\n// ...\nnavigate(\"/some-page\"); The navigate function can be used both on the client and on the server. Although there are some differences to be taken into account: If the navigation is done before sending the response (in the middleware, responseHeaders or an API endpoint for example), instead of modifying the navigation history it does a 301 redirect.\nIf it is done during rendering, SPA navigation or Server Action a soft redirect is made.\nIf used inside a client-event or a server-event (action) a new page is always generated in the navigation history. All i18n navigation rules apply equally in this function. navigate('/some') does not require you to use return navigate('/some') due to using the TypeScript never type.", "titles": [ "Linking and Navigating" ] @@ -5442,7 +5460,7 @@ { "id": "/building-your-application/routing/suspense-and-streaming#suspense-in-web-components", "title": "Suspense in Web-components", - "text": "By default all web-components are Server Side Rendered. Unless you use the skipSSR={true} attribute when consuming it: Web-components have another benefit of suspense, and that is that it is applied dynamically as well, this means that if you have web-components that are not displayed in the initial HTML but are dynamically displayed later after a user interaction and need to do something asynchronous to load data, the content defined in the \"suspense\" will be displayed while loading this data. src/web-components/my-web-component.tsx: export default async function MyWebComponent({}, { state }) {\n const foo = await fetch(/* ... */).then((r) => r.text());\n\n return
{foo}
;\n}\n\nMyWebComponent.suspense = (props, webContext) =>
loading...
; You can do a fetch in the render because in Brisa there are no rerenders, so it will always run only once mouting the component. Another benefit of web-components is the suspense defined therein is reactive to props, state, context and store. So you can make it interactive from the client if you need to. Example displaying different texts during suspense using store: import { WebContext } from \"brisa\";\n\nexport default async function MyWebComponent({}, { store }: WebContext) {\n store.set(\"suspense-message\", \"Loading step 1 ...\");\n const firstResponse = await fetch(/* ... */);\n store.set(\"suspense-message\", \"Loading step 2 ...\");\n const secondResponse = await fetch(/* ... */);\n\n return (\n
\n {firstResponse.foo} {secondResponse.bar}\n
\n );\n}\n\n// Display reactive messages from context during the suspense phase:\nMyWebComponent.suspense = ({}, { store }: WebContext) => {\n return store.get(\"suspense-message\");\n}; Also works during streaming. Although loading data is done at the client-side. That is, the suspense is rendered on the server with SSR, and on the client-side the real component is loaded by updating the suspense phase until it has the content. That is, these fetch inside the component will never be done from the server in the case of web-components.", + "text": "By default all web-components are Server Side Rendered. Unless you use the skipSSR={true} attribute when consuming it: Web-components have another benefit of suspense, and that is that it is applied dynamically as well, this means that if you have web-components that are not displayed in the initial HTML but are dynamically displayed later after a user interaction and need to do something asynchronous to load data, the content defined in the \"suspense\" will be displayed while loading this data. src/web-components/my-web-component.tsx: export default async function MyWebComponent({}, { state }) {\n const foo = await fetch(/* ... */).then((r) => r.text());\n\n return
{foo}
;\n}\n\nMyWebComponent.suspense = (props, webContext) =>
loading...
; You can do a fetch in the render because in Brisa there are no rerenders, so it will always run only once mounting the component. Another benefit of web-components is the suspense defined therein is reactive to props, state, context and store. So you can make it interactive from the client if you need to. Example displaying different texts during suspense using store: import { WebContext } from \"brisa\";\n\nexport default async function MyWebComponent({}, { store }: WebContext) {\n store.set(\"suspense-message\", \"Loading step 1 ...\");\n const firstResponse = await fetch(/* ... */);\n store.set(\"suspense-message\", \"Loading step 2 ...\");\n const secondResponse = await fetch(/* ... */);\n\n return (\n
\n {firstResponse.foo} {secondResponse.bar}\n
\n );\n}\n\n// Display reactive messages from context during the suspense phase:\nMyWebComponent.suspense = ({}, { store }: WebContext) => {\n return store.get(\"suspense-message\");\n}; Also works during streaming. Although loading data is done at the client-side. That is, the suspense is rendered on the server with SSR, and on the client-side the real component is loaded by updating the suspense phase until it has the content. That is, these fetch inside the component will never be done from the server in the case of web-components.", "titles": [ "Suspense and Streaming", "Suspense differences between server/web components"