diff --git a/docs/building-your-application/integrations/tailwind-css.md b/docs/building-your-application/integrations/tailwind-css.md index 22e239c6..73ad2917 100644 --- a/docs/building-your-application/integrations/tailwind-css.md +++ b/docs/building-your-application/integrations/tailwind-css.md @@ -44,6 +44,34 @@ And you are ready to use TailwindCSS in your Brisa project. > > Installing the dependencies manually, take care to use a TailwindCSS version `v.4.x`. +## Configuration + +You can configure TailwindCSS in your `brisa.config.ts` file: + +```ts +import brisaTailwindCSS from "brisa-tailwindcss"; + +export default { + integrations: [brisaTailwindCSS({ embedded: false })], +} satisfies Configuration; +``` + +The current configuration has only one option: + +- `embedded` (optional): If you want to embed the TailwindCSS CSS in the build output. Default is `true`. + +> [!NOTE] +> +> Tailwind needs a subdependency that cannot be compiled, which is [lightningcss](https://github.com/parcel-bundler/lightningcss), so the default is to treat it as external and then embed it inside build. + +### Type + +```ts +type Config = { + embedded?: boolean; +}; +``` + ## Defaults If you don't have any `.css` file with `@tailwind` directive or `tailwindcss` import, Brisa will automatically generate in build-time a default CSS file with TailwindCSS directives to be similar than [TailwindCSS CDN](https://tailwindcss.com/docs/installation/play-cdn): diff --git a/packages/brisa-tailwindcss/index.d.ts b/packages/brisa-tailwindcss/index.d.ts index ea87e2b4..8a6d8377 100644 --- a/packages/brisa-tailwindcss/index.d.ts +++ b/packages/brisa-tailwindcss/index.d.ts @@ -1,3 +1,7 @@ +type Config = { + embedded?: boolean; +}; + /** * To properly integrate TailwindCSS, you have to add the following code to * your `brisa.config.ts` file: @@ -12,7 +16,7 @@ * * - [Docs](https://brisa.build/building-your-application/integrations/tailwind-css#integrating-tailwind-css) */ -export default function tailwindCSS(): { +export default function tailwindCSS(config?: Config): { name: string; transpileCSS(pathname: string, content: string): Promise; defaultCSS: { diff --git a/packages/brisa-tailwindcss/index.test.ts b/packages/brisa-tailwindcss/index.test.ts index df24be54..85ee6106 100644 --- a/packages/brisa-tailwindcss/index.test.ts +++ b/packages/brisa-tailwindcss/index.test.ts @@ -1,11 +1,8 @@ import { describe, expect, it, spyOn } from 'bun:test'; import fs from 'node:fs/promises'; -import packageJSON from './package.json'; import libs from './libs.json'; import brisaTailwindcss from '.'; -const TAILWIND_VERSION = packageJSON.devDependencies.tailwindcss; - describe('brisa-tailwindcss', () => { it('should return the correct name', () => { const integration = brisaTailwindcss(); @@ -112,4 +109,23 @@ describe('brisa-tailwindcss', () => { mockCp.mockRestore(); mockExists.mockRestore(); }); + + it('should not embed tailwindcss when embedded is false', async () => { + const integration = brisaTailwindcss({ embedded: false }); + const mockLog = spyOn(console, 'log'); + const mockCp = spyOn(fs, 'cp').mockResolvedValue(); + const mockExists = spyOn(fs, 'exists').mockResolvedValue(true); + + await integration.afterBuild({ + BUILD_DIR: import.meta.dirname, + LOG_PREFIX: { INFO: 'INFO', WAIT: 'WAIT', TICK: 'TICK' }, + }); + + expect(mockLog).not.toHaveBeenCalled(); + expect(mockCp).not.toHaveBeenCalled(); + expect(mockExists).not.toHaveBeenCalled(); + mockLog.mockRestore(); + mockCp.mockRestore(); + mockExists.mockRestore(); + }); }); diff --git a/packages/brisa-tailwindcss/index.ts b/packages/brisa-tailwindcss/index.ts index 0bfbc7aa..5ead1152 100644 --- a/packages/brisa-tailwindcss/index.ts +++ b/packages/brisa-tailwindcss/index.ts @@ -4,8 +4,10 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import libs from './libs.json'; +const defaultConfig = { embedded: true }; + // Note: is not bundled here to avoid issues with lightningcss -export default function brisaTailwindcss() { +export default function brisaTailwindcss({ embedded = true } = defaultConfig) { return { name: 'brisa-tailwindcss', async transpileCSS(pathname: string, content: string) { @@ -30,6 +32,7 @@ export default function brisaTailwindcss() { // work correctly. As a solution, we install tailwind in the build folder and in this way the problem is solved. // Issue: https://github.com/brisa-build/brisa/issues/637 async afterBuild({ BUILD_DIR, LOG_PREFIX }) { + if (!embedded) return; const start = Date.now(); const destNodeModules = path.join(BUILD_DIR, 'node_modules'); const nodeModules = Bun.resolveSync('brisa', BUILD_DIR).split('brisa')[0]; diff --git a/packages/www/src/public/content.json b/packages/www/src/public/content.json index 03ea7d2a..56cb372c 100644 --- a/packages/www/src/public/content.json +++ b/packages/www/src/public/content.json @@ -4049,7 +4049,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.34\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.1.38\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" ] @@ -4275,6 +4275,23 @@ "Integrating Tailwind CSS v4" ] }, + { + "id": "/building-your-application/integrations/tailwind-css#configuration", + "title": "Configuration", + "text": "You can configure TailwindCSS in your brisa.config.ts file: import brisaTailwindCSS from \"brisa-tailwindcss\";\n\nexport default {\n integrations: [brisaTailwindCSS({ embedded: false })],\n} satisfies Configuration; The current configuration has only one option: embedded (optional): If you want to embed the TailwindCSS CSS in the build output. Default is true. Tailwind needs a subdependency that cannot be compiled, which is lightningcss, so the default is to treat it as external and then embed it inside build.", + "titles": [ + "Integrating Tailwind CSS v4" + ] + }, + { + "id": "/building-your-application/integrations/tailwind-css#type", + "title": "Type", + "text": "type Config = {\n embedded?: boolean;\n};", + "titles": [ + "Integrating Tailwind CSS v4", + "Configuration" + ] + }, { "id": "/building-your-application/integrations/tailwind-css#defaults", "title": "Defaults",