diff --git a/README.md b/README.md
index 95ec9d87ddcc..d713e64827fe 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,19 @@
+## Tailwind in browser
+changed the packages/@tailwindcss-browser project to use it as a library
+
+- clone it
+- add it in the package.js dependencies
+
+ `"@tailwindcss-browser": "file:../../tailwindcss-browser/packages/@tailwindcss-browser"`
+- install
+
+ `pnpm install`
+- import
+
+ `import { tailwindCompiler } from "@tailwindcss-browser";`
+
+
+---
diff --git a/packages/@tailwindcss-browser/package.json b/packages/@tailwindcss-browser/package.json
index 700cad815c0c..20ce420b82f7 100644
--- a/packages/@tailwindcss-browser/package.json
+++ b/packages/@tailwindcss-browser/package.json
@@ -18,10 +18,6 @@
"dev": "pnpm run build -- --watch",
"test:ui": "playwright test"
},
- "exports": {
- ".": "./dist/index.global.js",
- "./package.json": "./package.json"
- },
"files": [
"dist"
],
@@ -33,5 +29,12 @@
"h3": "^1.15.3",
"listhen": "^1.9.0",
"tailwindcss": "workspace:*"
+ },
+ "exports": {
+ ".": {
+ "require": "./dist/index.js",
+ "import": "./dist/index.mjs"
+ },
+ "./package.json": "./package.json"
}
-}
+}
\ No newline at end of file
diff --git a/packages/@tailwindcss-browser/src/index.ts b/packages/@tailwindcss-browser/src/index.ts
index 74992157f5d5..290f435dc4df 100644
--- a/packages/@tailwindcss-browser/src/index.ts
+++ b/packages/@tailwindcss-browser/src/index.ts
@@ -8,11 +8,6 @@ console.warn(
'The browser build of Tailwind CSS should not be used in production. To use Tailwind CSS in production, use the Tailwind CLI, Vite plugin, or PostCSS plugin: https://tailwindcss.com/docs/installation',
)
-/**
- * The type used by `` tags that contain input CSS.
- */
-const STYLE_TYPE = 'text/tailwindcss'
-
/**
* The current Tailwind CSS compiler.
*
@@ -21,33 +16,6 @@ const STYLE_TYPE = 'text/tailwindcss'
*/
let compiler: Awaited>
-/**
- * The list of all seen classes on the page so far. The compiler already has a
- * cache of classes but this lets us only pass new classes to `build(…)`.
- */
-let classes = new Set()
-
-/**
- * The last input CSS that was compiled. If stylesheets "change" without
- * actually changing, we can avoid a full rebuild.
- */
-let lastCss = ''
-
-/**
- * The stylesheet that we use to inject the compiled CSS into the page.
- */
-let sheet = document.createElement('style')
-
-/**
- * The queue of build tasks that need to be run. This is used to ensure that we
- * don't run multiple builds concurrently.
- */
-let buildQueue = Promise.resolve()
-
-/**
- * What build this is
- */
-let nextBuildId = 1
/**
* Used for instrumenting the build process. This data shows up in the
@@ -67,35 +35,7 @@ async function createCompiler() {
I.start(`Create compiler`)
I.start('Reading Stylesheets')
- // The stylesheets may have changed causing a full rebuild so we'll need to
- // gather the latest list of stylesheets.
- let stylesheets: Iterable = document.querySelectorAll(
- `style[type="${STYLE_TYPE}"]`,
- )
-
- let css = ''
- for (let sheet of stylesheets) {
- observeSheet(sheet)
- css += sheet.textContent + '\n'
- }
-
- // The user might have no stylesheets, or a some stylesheets without `@import`
- // because they want to customize their theme so we'll inject the main import
- // for them. However, if they start using `@import` we'll let them control
- // the build completely.
- if (!css.includes('@import')) {
- css = `@import "tailwindcss";${css}`
- }
-
- I.end('Reading Stylesheets', {
- size: css.length,
- changed: lastCss !== css,
- })
-
- // The input CSS did not change so the compiler does not need to be recreated
- if (lastCss === css) return
-
- lastCss = css
+ const css = `@import "tailwindcss";`
I.start('Compile CSS')
try {
@@ -108,8 +48,6 @@ async function createCompiler() {
I.end('Compile CSS')
I.end(`Create compiler`)
}
-
- classes.clear()
}
async function loadStylesheet(id: string, base: string) {
@@ -180,121 +118,28 @@ async function loadModule(): Promise {
throw new Error(`The browser build does not support plugins or config files.`)
}
-async function build(kind: 'full' | 'incremental') {
- if (!compiler) return
-
- // 1. Refresh the known list of classes
- let newClasses = new Set()
-
- I.start(`Collect classes`)
- for (let element of document.querySelectorAll('[class]')) {
- for (let c of element.classList) {
- if (classes.has(c)) continue
-
- classes.add(c)
- newClasses.add(c)
- }
- }
-
- I.end(`Collect classes`, {
- count: newClasses.size,
- })
-
- if (newClasses.size === 0 && kind === 'incremental') return
-
- // 2. Compile the CSS
- I.start(`Build utilities`)
-
- sheet.textContent = compiler.build(Array.from(newClasses))
-
- I.end(`Build utilities`)
-}
-
-function rebuild(kind: 'full' | 'incremental') {
+async function rebuild(classes: Set) {
async function run() {
- if (!compiler && kind !== 'full') {
- return
- }
- let buildId = nextBuildId++
-
- I.start(`Build #${buildId} (${kind})`)
-
- if (kind === 'full') {
+ if (!compiler) {
await createCompiler()
}
I.start(`Build`)
- await build(kind)
+ const result = compiler.build(Array.from(classes))
I.end(`Build`)
- I.end(`Build #${buildId} (${kind})`)
- }
-
- buildQueue = buildQueue.then(run).catch((err) => I.error(err))
-}
-
-// Handle changes to known stylesheets
-let styleObserver = new MutationObserver(() => rebuild('full'))
-
-function observeSheet(sheet: HTMLStyleElement) {
- styleObserver.observe(sheet, {
- attributes: true,
- attributeFilter: ['type'],
- characterData: true,
- subtree: true,
- childList: true,
- })
-}
-
-// Handle changes to the document that could affect the styles
-// - Changes to any element's class attribute
-// - New stylesheets being added to the page
-// - New elements (with classes) being added to the page
-new MutationObserver((records) => {
- let full = 0
- let incremental = 0
-
- for (let record of records) {
- // New stylesheets == tracking + full rebuild
- for (let node of record.addedNodes as Iterable) {
- if (node.nodeType !== Node.ELEMENT_NODE) continue
- if (node.tagName !== 'STYLE') continue
- if (node.getAttribute('type') !== STYLE_TYPE) continue
-
- observeSheet(node as HTMLStyleElement)
- full++
- }
-
- // New nodes require an incremental rebuild
- for (let node of record.addedNodes) {
- if (node.nodeType !== 1) continue
-
- // Skip the output stylesheet itself to prevent loops
- if (node === sheet) continue
-
- incremental++
- }
+ I.end(`Build`)
- // Changes to class attributes require an incremental rebuild
- if (record.type === 'attributes') {
- incremental++
- }
+ return result ?? '';
}
- if (full > 0) {
- return rebuild('full')
- } else if (incremental > 0) {
- return rebuild('incremental')
+ try {
+ return await Promise.resolve().then(run);;
+ } catch (error) {
+ I.error(error);
}
-}).observe(document.documentElement, {
- attributes: true,
- attributeFilter: ['class'],
- childList: true,
- subtree: true,
-})
-
-rebuild('full')
+}
+export const tailwindCompiler = rebuild;
-document.head.append(sheet)
diff --git a/packages/@tailwindcss-browser/tsconfig.json b/packages/@tailwindcss-browser/tsconfig.json
index 8ea040daf8d3..b9e1ccb07257 100644
--- a/packages/@tailwindcss-browser/tsconfig.json
+++ b/packages/@tailwindcss-browser/tsconfig.json
@@ -2,5 +2,14 @@
"extends": "../tsconfig.base.json",
"compilerOptions": {
"lib": ["es2022", "esnext.disposable", "dom", "dom.iterable"],
+ "target": "ESNext",
+ "module": "ESNext",
+ "declaration": true,
+ "declarationDir": "dist/types",
+ "outDir": "dist",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "strict": true,
},
+ "include": ["src"]
}
diff --git a/packages/@tailwindcss-browser/tsup.config.ts b/packages/@tailwindcss-browser/tsup.config.ts
index bb0ddc39cde4..654a9c0db5bc 100644
--- a/packages/@tailwindcss-browser/tsup.config.ts
+++ b/packages/@tailwindcss-browser/tsup.config.ts
@@ -1,9 +1,11 @@
import { defineConfig } from 'tsup'
export default defineConfig({
- format: ['iife'],
+ format: ['esm', 'cjs'],
clean: true,
minify: true,
+ sourcemap: true,
+ dts: true,
entry: ['src/index.ts'],
noExternal: [/.*/],
loader: {