tailwindcss/integrations/utils.ts

497 lines
16 KiB
TypeScript
Raw Normal View History

Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
import dedent from 'dedent'
import fastGlob from 'fast-glob'
import killPort from 'kill-port'
import { execSync, spawn } from 'node:child_process'
import fs from 'node:fs/promises'
import net from 'node:net'
import { homedir, platform, tmpdir } from 'node:os'
import path from 'node:path'
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
import { test as defaultTest, expect } from 'vitest'
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
const REPO_ROOT = path.join(__dirname, '..')
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
const PUBLIC_PACKAGES = (await fs.readdir(path.join(REPO_ROOT, 'dist'))).map((name) =>
name.replace('tailwindcss-', '@tailwindcss/').replace('.tgz', ''),
)
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
interface SpawnedProcess {
dispose: () => void
onStdout: (predicate: (message: string) => boolean) => Promise<void>
onStderr: (predicate: (message: string) => boolean) => Promise<void>
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
interface ChildProcessOptions {
cwd?: string
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
interface TestConfig {
fs: {
[filePath: string]: string
}
}
interface TestContext {
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
root: string
exec(command: string, options?: ChildProcessOptions): Promise<string>
spawn(command: string, options?: ChildProcessOptions): Promise<SpawnedProcess>
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
getFreePort(): Promise<number>
fs: {
write(filePath: string, content: string): Promise<void>
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
read(filePath: string): Promise<string>
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
glob(pattern: string): Promise<[string, string][]>
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
expectFileToContain(filePath: string, contents: string | string[]): Promise<void>
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
}
type TestCallback = (context: TestContext) => Promise<void> | void
interface TestFlags {
only?: boolean
debug?: boolean
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
type SpawnActor = { predicate: (message: string) => boolean; resolve: () => void }
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
const TEST_TIMEOUT = 30000
const ASSERTION_TIMEOUT = 5000
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
export function test(
name: string,
config: TestConfig,
testCallback: TestCallback,
{ only = false, debug = false }: TestFlags = {},
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
) {
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
return (only ? defaultTest.only : defaultTest)(
name,
{ timeout: TEST_TIMEOUT },
async (options) => {
let rootDir = debug
? path.join(REPO_ROOT, '.debug')
: // On Windows CI, tmpdir returns a path containing a weird RUNNER~1
// folder that apparently causes the vite builds to not work.
process.env.CI && platform() === 'win32'
? homedir()
: tmpdir()
await fs.mkdir(rootDir, { recursive: true })
let root = await fs.mkdtemp(path.join(rootDir, 'tailwind-integrations'))
if (debug) {
console.log('Running test in debug mode. File system will be written to:')
console.log(root)
console.log()
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
let context = {
root,
async exec(command: string, childProcessOptions: ChildProcessOptions = {}) {
let cwd = childProcessOptions.cwd ?? root
if (debug && cwd !== root) {
let relative = path.relative(root, cwd)
if (relative[0] !== '.') relative = `./${relative}`
console.log(`> cd ${relative}`)
}
if (debug) console.log(`> ${command}`)
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
return execSync(command, {
cwd,
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
stdio: 'pipe',
...childProcessOptions,
}).toString()
},
async spawn(command: string, childProcessOptions: ChildProcessOptions = {}) {
let resolveDisposal: (() => void) | undefined
let rejectDisposal: ((error: Error) => void) | undefined
let disposePromise = new Promise<void>((resolve, reject) => {
resolveDisposal = resolve
rejectDisposal = reject
})
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
let cwd = childProcessOptions.cwd ?? root
if (debug && cwd !== root) {
let relative = path.relative(root, cwd)
if (relative[0] !== '.') relative = `./${relative}`
console.log(`> cd ${relative}`)
}
if (debug) console.log(`>& ${command}`)
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
let child = spawn(command, {
cwd,
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
shell: true,
env: {
...process.env,
},
...childProcessOptions,
})
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
function dispose() {
child.kill()
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
let timer = setTimeout(
() =>
rejectDisposal?.(new Error(`spawned process (${command}) did not exit in time`)),
ASSERTION_TIMEOUT,
)
disposePromise.finally(() => {
clearTimeout(timer)
})
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
return disposePromise
}
disposables.push(dispose)
function onExit() {
resolveDisposal?.()
}
let stdoutMessages: string[] = []
let stderrMessages: string[] = []
let stdoutActors: SpawnActor[] = []
let stderrActors: SpawnActor[] = []
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
function notifyNext(actors: SpawnActor[], messages: string[]) {
if (actors.length <= 0) return
let [next] = actors
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
for (let [idx, message] of messages.entries()) {
if (next.predicate(message)) {
messages.splice(0, idx + 1)
let actorIdx = actors.indexOf(next)
actors.splice(actorIdx, 1)
next.resolve()
break
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
let combined: ['stdout' | 'stderr', string][] = []
child.stdout.on('data', (result) => {
let content = result.toString()
if (debug) console.log(content)
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
combined.push(['stdout', content])
stdoutMessages.push(content)
notifyNext(stdoutActors, stdoutMessages)
})
child.stderr.on('data', (result) => {
let content = result.toString()
if (debug) console.error(content)
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
combined.push(['stderr', content])
stderrMessages.push(content)
notifyNext(stderrActors, stderrMessages)
})
child.on('exit', onExit)
child.on('error', (error) => {
if (error.name !== 'AbortError') {
throw error
}
})
options.onTestFailed(() => {
// In debug mode, messages are logged to the console immediatly
if (debug) return
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
for (let [type, message] of combined) {
if (type === 'stdout') {
console.log(message)
} else {
console.error(message)
}
}
})
return {
dispose,
onStdout(predicate: (message: string) => boolean) {
return new Promise<void>((resolve) => {
stdoutActors.push({ predicate, resolve })
notifyNext(stdoutActors, stdoutMessages)
})
},
onStderr(predicate: (message: string) => boolean) {
return new Promise<void>((resolve) => {
stderrActors.push({ predicate, resolve })
notifyNext(stderrActors, stderrMessages)
})
},
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
},
async getFreePort(): Promise<number> {
return new Promise((resolve, reject) => {
let server = net.createServer()
server.listen(0, () => {
let address = server.address()
let port = address === null || typeof address === 'string' ? null : address.port
server.close(() => {
if (port === null) {
reject(new Error(`Failed to get a free port: address is ${address}`))
} else {
disposables.push(async () => {
// Wait for 10ms in case the process was just killed
await new Promise((resolve) => setTimeout(resolve, 10))
// kill-port uses `lsof` on macOS which is expensive and can
// block for multiple seconds. In order to avoid that for a
// server that is no longer running, we check if the port is
// still in use first.
let isPortTaken = await testIfPortTaken(port)
if (!isPortTaken) {
return
}
await killPort(port)
})
resolve(port)
}
})
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
})
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
})
},
fs: {
async write(filename: string, content: string): Promise<void> {
let full = path.join(root, filename)
if (filename.endsWith('package.json')) {
content = await overwriteVersionsInPackageJson(content)
}
// Ensure that files written on Windows use \r\n line ending
if (platform() === 'win32') {
content = content.replace(/\n/g, '\r\n')
}
let dir = path.dirname(full)
await fs.mkdir(dir, { recursive: true })
await fs.writeFile(full, content)
},
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
read(filePath: string) {
return fs.readFile(path.resolve(root, filePath), 'utf8')
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
},
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
async glob(pattern: string) {
let files = await fastGlob(pattern, { cwd: root })
return Promise.all(
files.map(async (file) => {
let content = await fs.readFile(path.join(root, file), 'utf8')
return [file, content]
}),
)
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
},
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
async expectFileToContain(filePath, contents) {
return retryUntil(async () => {
let fileContent = await this.read(filePath)
for (let content of contents) {
expect(fileContent).toContain(content)
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
})
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
},
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
},
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
} satisfies TestContext
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
for (let [filename, content] of Object.entries(config.fs)) {
await context.fs.write(filename, content)
}
try {
// In debug mode, the directory is going to be inside the pnpm workspace
// of the tailwindcss package. This means that `pnpm install` will run
// pnpm install on the workspace instead (expect if the root dir defines
// a separate workspace). We work around this by using the
// `--ignore-workspace` flag.
let ignoreWorkspace = debug && !config.fs['pnpm-workspace.yaml']
context.exec(`pnpm install${ignoreWorkspace ? ' --ignore-workspace' : ''}`)
} catch (error: any) {
console.error(error)
throw error
}
let disposables: (() => Promise<void>)[] = []
async function dispose() {
await Promise.all(disposables.map((dispose) => dispose()))
// Skip removing the directory in CI beause it can stall on Windows
if (!process.env.CI && !debug) {
await fs.rm(root, { recursive: true, force: true })
}
}
options.onTestFinished(dispose)
return await testCallback(context)
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
},
)
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
test.only = (name: string, config: TestConfig, testCallback: TestCallback) => {
return test(name, config, testCallback, { only: true })
}
test.debug = (name: string, config: TestConfig, testCallback: TestCallback) => {
return test(name, config, testCallback, { only: true, debug: true })
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
// Maps package names to their tarball filenames. See scripts/pack-packages.ts
// for more details.
function pkgToFilename(name: string) {
return `${name.replace('@', '').replace('/', '-')}.tgz`
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
async function overwriteVersionsInPackageJson(content: string): Promise<string> {
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
let json = JSON.parse(content)
// Resolve all workspace:^ versions to local tarballs
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
;['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'].forEach(
(key) => {
let dependencies = json[key] || {}
for (let dependency in dependencies) {
if (dependencies[dependency] === 'workspace:^') {
dependencies[dependency] = resolveVersion(dependency)
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
},
)
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
// Inject transitive dependency overwrite. This is necessary because
// @tailwindcss/vite internally depends on a specific version of
// @tailwindcss/oxide and we instead want to resolve it to the locally built
// version.
json.pnpm ||= {}
json.pnpm.overrides ||= {}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
for (let pkg of PUBLIC_PACKAGES) {
json.pnpm.overrides[pkg] = resolveVersion(pkg)
}
Add integration test setup and tests for the Vite integration (#14089) This PR adds a new root `/integrations` folder that will be the home of integration tests. The idea of these tests is to use Tailwind in various setups just like our users would (by only using the publishable npm builds). To avoid issues with concurrent tests making changes to the file system, to make it very easy to test through a range of versions, and to avoid changing configuration objects over and over in test runs, we decided to inline the scaffolding completely into the test file and have no examples checked into the repo. Here's an example of how this can look like for a simple Vite test: ```ts test('works with production builds', { fs: { 'package.json': json` { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, "devDependencies": { "vite": "^5.3.5" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()], }) `, 'index.html': html` <head> <link rel="stylesheet" href="./src/index.css"> </head> <body> <div class="underline m-2">Hello, world!</div> </body> `, 'src/index.css': css` @import 'tailwindcss/theme' reference; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec }) => { await exec('pnpm vite build') expect.assertions(2) for (let [path, content] of await fs.glob('dist/**/*.css')) { expect(path).toMatch(/\.css$/) expect(stripTailwindComment(content)).toMatchInlineSnapshot( ` ".m-2 { margin: var(--spacing-2, .5rem); } .underline { text-decoration-line: underline; }" `, ) } }, ) ``` By defining all dependencies this way, we never have to worry about which fixtures are checked in and can more easily describe changes to the setup. For ergonomics, we've also added the [`embed` prettier plugin](https://github.com/Sec-ant/prettier-plugin-embed). This will mean that files inlined in the `fs` setup are properly indented. No extra work needed! If you're using VS Code, I can also recommend the [Language Literals](https://marketplace.visualstudio.com/items?itemName=sissel.language-literals) extension so that syntax highlighting also _just works_. A neat feature of inlining the scaffolding like this is to make it very simple to test through a variety of versions. For example, here's how we can set up a test against Vite 5 and Vite 4: ```js ;['^4.5.3', '^5.3.5'].forEach(viteVersion => { test(`works with production builds for Vite ${viteVersion}`, { fs: { 'package.json': json` { "type": "module", "devDependencies": { "vite": "${viteVersion}" } } `, async () => { // Do something }, ) }) ``` ## Philosophy Before we dive into the specifics, I want to clearly state the design considerations we have chosen for this new test suite: - All file mutations should be done in temp folders, nothing should ever mess with your working directory - Windows as a first-class citizen - Have a clean and simple API that describes the test setup only using public APIs - Focus on reliability (make sure cleanup scripts work and are tolerant to various error scenarios) - If a user reports an issue with a specific configuration, we want to be able to reproduce them with integration tests, no matter how obscure the setup (this means the test need to be in control of most of the variables) - Tests should be reasonably fast (obviously this depends on the integration. If we use a slow build tool, we can't magically speed it up, but our overhead should be minimal). ## How it works The current implementation provides a custom `test` helper function that, when used, sets up the environment according to the configuration. It'll create a new temporary directory and create all files, ensuring things like proper `\r\n` line endings on Windows. We do have to patch the `package.json` specifically, since we can not use public versions of the tailwindcss packages as we want to be able to test against a development build. To make this happen, every `pnpm build` run now creates tarballs of the npm modules (that contain only the files that would also in the published build). We then patch the `package.json` to rewrite `workspace:^` versions to link to those tarballs. We found this to work reliably on Windows and macOS as well as being fast enough to not cause any issues. Furthermore we also decided to use `pnpm` as the version manager for integration tests because of it's global module cache (so installing `vite` is fast as soon as you installed it once). The test function will receive a few utilities that it can use to more easily interact with the temp dir. One example is a `fs.glob` function that you can use to easily find files in eventual `dist/` directories or helpers around `spawn` and `exec` that make sure that processes are cleaned up correctly. Because we use tarballs from our build dependencies, working on changes requires a workflow where you run `pnpm build` before running `pnpm test:integrations`. However it also means we can run clients like our CLI client with no additional overhead—just install the dependency like any user would and set up your test cases this way. ## Test plan This PR also includes two Vite specific integration tests: One testing a static build (`pnpm vite build`) and one a dev mode build (`pnpm vite dev`) that also makes changes to the file system and asserts that the resources properly update. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 11:50:49 +02:00
return JSON.stringify(json, null, 2)
}
function resolveVersion(dependency: string) {
let tarball = path.join(REPO_ROOT, 'dist', pkgToFilename(dependency))
return `file:${tarball}`
}
export function stripTailwindComment(content: string) {
return content.replace(/\/\*! tailwindcss .*? \*\//g, '').trim()
}
function testIfPortTaken(port: number): Promise<boolean> {
return new Promise((resolve) => {
let client = new net.Socket()
client.once('connect', () => {
resolve(true)
client.end()
})
client.once('error', (error: any) => {
if (error.code !== 'ECONNREFUSED') {
resolve(true)
} else {
resolve(false)
}
client.end()
})
client.connect({ port: port, host: 'localhost' })
})
}
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
export let css = dedent
export let html = dedent
export let ts = dedent
export let js = dedent
export let json = dedent
export let yaml = dedent
export let txt = dedent
export function candidate(strings: TemplateStringsArray, ...values: any[]) {
let output: string[] = []
for (let i = 0; i < strings.length; i++) {
output.push(strings[i])
if (i < values.length) {
output.push(values[i])
}
}
return `.${escape(output.join('').trim())}`
}
// https://drafts.csswg.org/cssom/#serialize-an-identifier
export function escape(value: string) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.')
}
var string = String(value)
var length = string.length
var index = -1
var codeUnit
var result = ''
var firstCodeUnit = string.charCodeAt(0)
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
length == 1 &&
firstCodeUnit == 0x002d
) {
return '\\' + string
}
while (++index < length) {
codeUnit = string.charCodeAt(index)
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD'
continue
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001f) ||
codeUnit == 0x007f ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002d)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' '
continue
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002d ||
codeUnit == 0x005f ||
(codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
(codeUnit >= 0x0041 && codeUnit <= 0x005a) ||
(codeUnit >= 0x0061 && codeUnit <= 0x007a)
) {
// the character itself
result += string.charAt(index)
continue
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index)
}
return result
}
async function retryUntil<T>(
fn: () => Promise<T>,
{ timeout = ASSERTION_TIMEOUT, delay = 5 }: { timeout?: number; delay?: number } = {},
) {
let end = Date.now() + timeout
let error: any
while (Date.now() < end) {
try {
return await fn()
} catch (err) {
error = err
await new Promise((resolve) => setTimeout(resolve, delay))
}
}
throw error
}