├── .changeset
├── README.md
└── config.json
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── config.yml
└── workflows
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .npmrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── SECURITY.md
├── apps
├── .gitignore
├── astro-app
│ ├── astro.config.mjs
│ ├── package.json
│ ├── public
│ │ └── robots.txt
│ ├── src
│ │ ├── env.d.ts
│ │ └── pages
│ │ │ └── index.astro
│ └── tsconfig.json
├── next-app-router
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── next.config.mjs
│ ├── package.json
│ ├── postcss.config.mjs
│ ├── public
│ │ ├── next.svg
│ │ └── vercel.svg
│ ├── tailwind.config.ts
│ ├── tailwindcss-mangle.config.ts
│ └── tsconfig.json
├── next-app
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── README.md
│ ├── next.config.js
│ ├── package.json
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api
│ │ │ └── hello.ts
│ │ └── index.tsx
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── next.svg
│ │ └── vercel.svg
│ ├── styles
│ │ └── globals.css
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ └── tsconfig.json
├── nuxt-app
│ ├── .gitignore
│ ├── .npmrc
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── app.vue
│ ├── assets
│ │ ├── css
│ │ │ └── main.css
│ │ ├── next.svg
│ │ └── vercel.svg
│ ├── nuxt.config.ts
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ └── tsconfig.json
├── remix-app
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── app
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── root.tsx
│ │ ├── routes
│ │ │ └── _index.tsx
│ │ └── tailwind.css
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ └── tsconfig.json
├── solid-app
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── postcss.config.js
│ ├── src
│ │ ├── App.module.css
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ └── favicon.ico
│ │ ├── index.css
│ │ ├── index.tsx
│ │ └── logo.svg
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── vite-lit
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── lit.svg
│ │ ├── index.css
│ │ ├── my-element.ts
│ │ └── vite-env.d.ts
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── vite-react
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── index.scss
│ │ ├── main.tsx
│ │ ├── next.tsx
│ │ ├── utils.ts
│ │ └── vite-env.d.ts
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── vite-svelte
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── .vscode
│ │ └── extensions.json
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.cjs
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.svelte
│ │ ├── app.css
│ │ ├── assets
│ │ │ └── svelte.svg
│ │ ├── lib
│ │ │ └── Counter.svelte
│ │ ├── main.ts
│ │ └── vite-env.d.ts
│ ├── svelte.config.js
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── vite-vanilla
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── counter.ts
│ │ ├── main.ts
│ │ ├── style.css
│ │ ├── typescript.svg
│ │ └── vite-env.d.ts
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── vite-vue
│ ├── .gitignore
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── .vscode
│ │ └── extensions.json
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ └── vue.svg
│ │ ├── components
│ │ │ └── HelloWorld.vue
│ │ ├── index.scss
│ │ ├── main.ts
│ │ ├── style.css
│ │ └── vite-env.d.ts
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── webpack5-vue3
│ ├── .browserslistrc
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .tw-patch
│ └── tw-class-list.json
│ ├── babel.config.js
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ ├── favicon.ico
│ └── index.html
│ ├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── shims-vue.d.ts
│ └── views
│ │ ├── AboutView.vue
│ │ └── HomeView.vue
│ ├── tailwind.config.js
│ ├── tailwindcss-mangle.config.ts
│ ├── tsconfig.json
│ └── vue.config.js
├── assets
└── package.json
├── commitlint.config.ts
├── eslint.config.js
├── lint-staged.config.js
├── package.json
├── packages
├── config
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ │ ├── config.ts
│ │ ├── constants.ts
│ │ ├── defaults.ts
│ │ ├── index.ts
│ │ └── types.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── config.test.ts.snap
│ │ │ ├── defaults.test.ts.snap
│ │ │ └── index.test.ts.snap
│ │ ├── config.test.ts
│ │ ├── defaults.test.ts
│ │ ├── fixtures
│ │ │ └── config
│ │ │ │ ├── 0.default
│ │ │ │ └── tailwindcss-mangle.config.ts
│ │ │ │ ├── 1.change-options
│ │ │ │ └── tailwindcss-mangle.config.ts
│ │ │ │ ├── 2.mangle-options
│ │ │ │ └── tailwindcss-mangle.config.ts
│ │ │ │ └── initConfig
│ │ │ │ └── tailwindcss-mangle.config.ts
│ │ ├── index.test.ts
│ │ └── utils.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ └── vitest.config.ts
├── core
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── babel
│ │ │ └── index.ts
│ │ ├── constants.ts
│ │ ├── css
│ │ │ ├── index.ts
│ │ │ └── plugins.ts
│ │ ├── ctx
│ │ │ └── index.ts
│ │ ├── env.ts
│ │ ├── html
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── js
│ │ │ ├── index.ts
│ │ │ └── utils.ts
│ │ ├── math.ts
│ │ ├── shared.ts
│ │ └── types.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── css.test.ts.snap
│ │ │ ├── html.test.ts.snap
│ │ │ ├── index.test.ts.snap
│ │ │ └── js.test.ts.snap
│ │ ├── css.test.ts
│ │ ├── exports.test.ts
│ │ ├── fixtures
│ │ │ ├── app0.json
│ │ │ ├── app0.tsx
│ │ │ ├── comment-ignore.js
│ │ │ ├── css-loader.js
│ │ │ ├── hello-world.css
│ │ │ ├── hello-world.html
│ │ │ ├── hello-world.js
│ │ │ ├── next-app-dev-inline-tw.js
│ │ │ ├── next-server-page.js
│ │ │ ├── nuxt-app-all-class-set.json
│ │ │ ├── nuxt-app-partial-class-set.json
│ │ │ ├── nuxt-raw-page.css
│ │ │ ├── nuxt-raw-page.js
│ │ │ ├── package.json
│ │ │ ├── preserve-fn-case0.js
│ │ │ ├── preserve-fn-case0.ts
│ │ │ ├── preserve-fn-case0.vue
│ │ │ ├── preserve-fn-case1.json
│ │ │ ├── preserve-fn-case1.vue
│ │ │ ├── preserve-fn-case2.json
│ │ │ ├── preserve-fn-case2.vue
│ │ │ ├── prod
│ │ │ │ ├── 0.js
│ │ │ │ └── 1.js
│ │ │ ├── tailwind.config.js
│ │ │ ├── trailing-slash-0.html
│ │ │ ├── trailing-slash-0.js
│ │ │ ├── trailing-slash-1.js
│ │ │ ├── trailing-slash-2.js
│ │ │ ├── trailing-slash.html
│ │ │ ├── tw-class-set.json
│ │ │ ├── vanilla-0.json
│ │ │ ├── vanilla-0.ts
│ │ │ ├── vite-chunk.js
│ │ │ ├── vite-lit.js
│ │ │ ├── vue-build-dist.js
│ │ │ ├── vue.scoped.css
│ │ │ └── webpack-dev-content.js
│ │ ├── html.test.ts
│ │ ├── index.test.ts
│ │ ├── js.test.ts
│ │ └── utils
│ │ │ ├── index.ts
│ │ │ ├── svelte-to-tsx.ts
│ │ │ └── vue-to-tsx.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ └── vitest.config.ts
├── shared
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── classGenerator.ts
│ │ ├── index.ts
│ │ ├── regex.ts
│ │ ├── split.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── classGenerator.test.ts.snap
│ │ │ ├── reg.test.ts.snap
│ │ │ └── split.test.ts.snap
│ │ ├── classGenerator.test.ts
│ │ ├── reg.test.ts
│ │ └── split.test.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ └── vitest.config.ts
├── tailwindcss-patch
│ ├── .tw-patch
│ │ └── tw-class-list.json
│ ├── CHANGELOG.md
│ ├── README-cn.md
│ ├── README.md
│ ├── bin
│ │ └── tw-patch.js
│ ├── dev
│ │ └── bin.ts
│ ├── draft.md
│ ├── how-it-works.md
│ ├── index.css
│ ├── package.json
│ ├── src
│ │ ├── babel
│ │ │ └── index.ts
│ │ ├── cli.ts
│ │ ├── constants.ts
│ │ ├── core
│ │ │ ├── cache.ts
│ │ │ ├── candidates.ts
│ │ │ ├── index.ts
│ │ │ ├── patcher.ts
│ │ │ ├── patches
│ │ │ │ ├── exportContext
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── postcss-v2.ts
│ │ │ │ │ └── postcss-v3.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── supportCustomUnits
│ │ │ │ │ └── index.ts
│ │ │ ├── postcss.ts
│ │ │ └── runtime.ts
│ │ ├── defaults.ts
│ │ ├── index.ts
│ │ ├── logger.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── context.test.ts.snap
│ │ │ ├── defaults.test.ts.snap
│ │ │ ├── index.test.ts.snap
│ │ │ ├── inspector.test.ts.snap
│ │ │ ├── patch.test.ts.snap
│ │ │ ├── postcss7-v2.test.ts.snap
│ │ │ ├── postcss8-v3.test.ts.snap
│ │ │ └── v4.test.ts.snap
│ │ ├── cache.test.ts
│ │ ├── config.test.ts
│ │ ├── defaults.test.ts
│ │ ├── fixtures
│ │ │ ├── apps
│ │ │ │ ├── 0.common
│ │ │ │ │ ├── .tw-patch
│ │ │ │ │ │ └── tw-class-list.json
│ │ │ │ │ ├── package.json
│ │ │ │ │ ├── postcss.config.js
│ │ │ │ │ ├── src
│ │ │ │ │ │ └── index.html
│ │ │ │ │ ├── tailwind.config.js
│ │ │ │ │ ├── tailwindcss-mangle.config.ts
│ │ │ │ │ └── tailwindcss-patch.config.ts
│ │ │ │ └── 1.default
│ │ │ │ │ ├── .tw-patch
│ │ │ │ │ └── tw-class-list.json
│ │ │ │ │ ├── package.json
│ │ │ │ │ ├── postcss.config.js
│ │ │ │ │ ├── src
│ │ │ │ │ └── index.html
│ │ │ │ │ ├── tailwind.config.js
│ │ │ │ │ ├── tailwindcss-mangle.config.ts
│ │ │ │ │ └── tailwindcss-patch.config.ts
│ │ │ ├── cache
│ │ │ │ ├── index.json
│ │ │ │ ├── merge-multiple-context.json
│ │ │ │ └── raw-method.json
│ │ │ ├── cli
│ │ │ │ └── index.css
│ │ │ ├── config
│ │ │ │ ├── 0.default
│ │ │ │ │ └── tailwindcss-mangle.config.ts
│ │ │ │ └── 1.change-options
│ │ │ │ │ ├── tailwindcss-mangle.config.ts
│ │ │ │ │ └── tailwindcss-patch.config.ts
│ │ │ ├── hello-world.css
│ │ │ ├── hello-world.html
│ │ │ ├── hello-world.js
│ │ │ ├── hello-world.wxml
│ │ │ ├── img-url.jsx
│ │ │ ├── postcss7-compat
│ │ │ │ └── lib
│ │ │ │ │ └── jit
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── processTailwindFeatures.js
│ │ │ ├── trailing-slash.vue
│ │ │ ├── v4
│ │ │ │ ├── .gitignore
│ │ │ │ ├── deep
│ │ │ │ │ └── index.html
│ │ │ │ ├── index.css
│ │ │ │ ├── index.html
│ │ │ │ └── patch
│ │ │ │ │ └── dist
│ │ │ │ │ ├── a.mjs
│ │ │ │ │ ├── chunk-V2K3XTS4.mjs
│ │ │ │ │ ├── default-theme.js
│ │ │ │ │ └── lib.js
│ │ │ └── versions
│ │ │ │ ├── 2
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── jit
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ └── processTailwindFeatures.js
│ │ │ │ │ └── processTailwindFeatures.js
│ │ │ │ └── package.json
│ │ │ │ ├── .eslintignore
│ │ │ │ ├── .eslintrc.cjs
│ │ │ │ ├── 3.0.0
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.1
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.2
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.3
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.4
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.6
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.2.7
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.0
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.1
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.2
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.3
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.4
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.5
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.6
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.3.7
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.0
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.1
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.12
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.14
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.2
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.3
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.4
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.5
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.6
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── 3.4.7
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── README.md
│ │ │ │ ├── copy.js
│ │ │ │ ├── install.js
│ │ │ │ ├── lts
│ │ │ │ ├── lib
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── plugin.js
│ │ │ │ │ ├── processTailwindFeatures.js
│ │ │ │ │ └── util
│ │ │ │ │ │ └── dataTypes.js
│ │ │ │ └── package.json
│ │ │ │ ├── package.json
│ │ │ │ ├── utils.js
│ │ │ │ └── yarn.lock
│ │ ├── index.test.ts
│ │ ├── inspector.test.ts
│ │ ├── patch.test.ts
│ │ ├── pkg.test.ts
│ │ ├── postcss7-v2.test.ts
│ │ ├── postcss8-v3.test.ts
│ │ ├── splice-changes-into-string.ts
│ │ ├── src
│ │ │ ├── candidate.ts
│ │ │ ├── utils
│ │ │ │ └── design-system.ts
│ │ │ └── value-parser.ts
│ │ ├── tailwindcss4.test.ts
│ │ ├── tw-patcher.test.ts
│ │ ├── utils.test.ts
│ │ ├── utils.ts
│ │ └── v4.test.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ ├── vitest.config.ts
│ └── vitest.setup.ts
└── unplugin-tailwindcss-mangle
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── constants.ts
│ ├── core
│ │ ├── factory.ts
│ │ ├── index.ts
│ │ └── plugin.ts
│ ├── esbuild.ts
│ ├── globals.d.ts
│ ├── index.ts
│ ├── loader.ts
│ ├── nuxt.ts
│ ├── rollup.ts
│ ├── types.ts
│ ├── utils.ts
│ ├── vite.ts
│ └── webpack.ts
│ ├── test
│ ├── __snapshots__
│ │ ├── babel.test.ts.snap
│ │ ├── fallback.test.ts.snap
│ │ ├── pre.test.ts.snap
│ │ ├── vite.test.ts.snap
│ │ └── webpack.test.ts.snap
│ ├── context.test.ts
│ ├── fixtures
│ │ ├── css
│ │ │ ├── vite-vanilla.after.css
│ │ │ └── vite-vanilla.before.css
│ │ ├── fallback
│ │ │ ├── index.json
│ │ │ ├── index.vue
│ │ │ └── tailwindcss-mangle.config.ts
│ │ ├── ts
│ │ │ ├── .tw-patch
│ │ │ │ └── tw-class-list.json
│ │ │ └── vanilla-0.ts
│ │ ├── tsx
│ │ │ ├── .tw-patch
│ │ │ │ └── tw-class-list.json
│ │ │ ├── app.tsx
│ │ │ └── app0.tsx
│ │ ├── vite-repo
│ │ │ ├── .gitignore
│ │ │ ├── .gitkeep
│ │ │ ├── .tw-patch
│ │ │ │ └── tw-class-list.json
│ │ │ ├── index.html
│ │ │ ├── package.json
│ │ │ ├── postcss.config.cjs
│ │ │ ├── src
│ │ │ │ ├── counter.ts
│ │ │ │ ├── main.ts
│ │ │ │ ├── style.css
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── tailwind.config.cjs
│ │ │ └── tsconfig.json
│ │ └── webpack-repo
│ │ │ ├── .gitkeep
│ │ │ ├── .tw-patch
│ │ │ └── tw-class-list.json
│ │ │ ├── package.json
│ │ │ ├── postcss.config.js
│ │ │ ├── src
│ │ │ ├── index.css
│ │ │ ├── index.html
│ │ │ └── index.js
│ │ │ └── tailwind.config.js
│ ├── vite.test.ts
│ └── webpack.test.ts
│ ├── tsconfig.json
│ ├── tsup.config.ts
│ ├── vitest.config.ts
│ └── vitest.setup.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── renovate.json
├── scripts
└── postcss7-compat
│ ├── CHANGELOG.md
│ ├── index.js
│ ├── package.json
│ └── result.css
├── stylelint.config.js
├── tsconfig.json
├── turbo.json
├── vitest.workspace.ts
└── website
├── .gitignore
├── .tw-patch
└── tw-class-list.json
├── CHANGELOG.md
├── app
├── [lang]
│ ├── [[...mdxPath]]
│ │ └── page.tsx
│ ├── layout.tsx
│ ├── not-found.ts
│ └── styles.css
├── _components
│ ├── authors.tsx
│ └── features.css
├── _dictionaries
│ ├── en.ts
│ ├── get-dictionary.ts
│ ├── i18n-config.ts
│ └── zh.ts
└── env.d.ts
├── content
├── en
│ ├── _meta.js
│ ├── config.mdx
│ ├── index.mdx
│ ├── mangle.mdx
│ ├── patch.mdx
│ └── recommend.mdx
└── zh
│ ├── _meta.js
│ ├── config.mdx
│ ├── index.mdx
│ ├── mangle.mdx
│ ├── patch.mdx
│ └── recommend.mdx
├── mdx-components.ts
├── middleware.ts
├── next-env.d.ts
├── next.config.ts
├── package.json
├── postcss.config.js
├── scripts
└── translate.ts
├── tailwind.config.ts
└── tsconfig.json
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4 | with multi-package repos, or single-package repos to help you version and publish your code. You can
5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json",
3 | "changelog": [
4 | "@changesets/changelog-github",
5 | {
6 | "repo": "sonofmagic/tailwindcss-mangle"
7 | }
8 | ],
9 | "commit": false,
10 | "fixed": [],
11 | "linked": [],
12 | "access": "public",
13 | "baseBranch": "main",
14 | "updateInternalDependencies": "patch",
15 | "ignore": []
16 | }
17 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .git
3 | .gitignore
4 | *.md
5 | dist
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = false
12 | insert_final_newline = false
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository
2 |
3 | github: [sonofmagic]
4 | custom: ['https://github.com/sonofmagic/sponsors']
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Feature Request
4 | url: https://github.com/sonofmagic/monorepo-template/discussions
5 | about: Suggest new features for consideration
6 | # - name: Discord Chat
7 | # url: https://chat.vuejs.org
8 | # about: Ask questions and discuss with other Vue users in real time.
9 | # - name: Questions & Discussions
10 | # url: https://github.com/vuejs/core/discussions
11 | # about: Use GitHub discussions for message-board style questions and discussions.
12 | # - name: Patreon
13 | # url: https://www.patreon.com/evanyou
14 | # about: Love Vue.js? Please consider supporting us via Patreon.
15 | # - name: Open Collective
16 | # url: https://opencollective.com/vuejs/donate
17 | # about: Love Vue.js? Please consider supporting us via Open Collective.
18 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | # push:
5 | # branches: ['main']
6 | pull_request:
7 | types: [opened, synchronize]
8 | workflow_dispatch:
9 |
10 | permissions:
11 | contents: read
12 |
13 | jobs:
14 | build:
15 | name: Build and Test
16 | timeout-minutes: 15
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | os: [ubuntu-latest, windows-latest, macos-latest]
21 | node-version: [18, 20, 22]
22 | runs-on: ${{ matrix.os }}
23 | # To use Remote Caching, uncomment the next lines and follow the steps below.
24 | # env:
25 | # TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
26 | # TURBO_TEAM: ${{ vars.TURBO_TEAM }}
27 |
28 | steps:
29 | - name: Check out code
30 | uses: actions/checkout@v4
31 | with:
32 | fetch-depth: 2
33 |
34 | - uses: pnpm/action-setup@v4
35 |
36 | - name: Setup Node.js environment
37 | uses: actions/setup-node@v4
38 | with:
39 | node-version: ${{ matrix.node-version }}
40 | cache: pnpm
41 |
42 | - name: Install dependencies
43 | run: pnpm install
44 |
45 | - name: Build
46 | run: pnpm build
47 |
48 | - name: Test
49 | run: pnpm test
50 |
51 | - name: Upload coverage reports to Codecov
52 | uses: codecov/codecov-action@v5
53 | env:
54 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # next.js
12 | .next/
13 | out/
14 | build
15 |
16 | # misc
17 | .DS_Store
18 | *.pem
19 |
20 | # debug
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | .pnpm-debug.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
32 | # turbo
33 | .turbo
34 | dist
35 | .nuxt
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | pnpm dlx commitlint --edit $1
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | pnpm lint-staged
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=http://registry.npmmirror.com/
2 | shamefully-hoist=true
3 | git-checks=false
4 | hoist-pattern[]=!tailwindcss
5 | auto-install-peers=false
6 | package-manager-strict=false
7 | public-hoist-pattern[]=*@nextui-org/*
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "stylelint.vscode-stylelint"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:22-alpine AS base
2 | ENV PNPM_HOME="/pnpm"
3 | ENV PATH="$PNPM_HOME:$PATH"
4 | RUN corepack enable
5 |
6 | FROM base AS builder
7 | COPY . /usr/src/app
8 | WORKDIR /usr/src/app
9 | RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
10 | RUN pnpm run -r build
11 | RUN pnpm deploy --filter=@icebreakers/foo --prod /prod/foo
12 | RUN pnpm deploy --filter=@icebreakers/bar --prod /prod/bar
13 |
14 | FROM base AS foo
15 | COPY --from=builder /prod/foo /prod/foo
16 | WORKDIR /prod/foo
17 | EXPOSE 8000
18 | CMD [ "pnpm", "start" ]
19 |
20 | FROM base AS bar
21 | COPY --from=builder /prod/bar /prod/bar
22 | WORKDIR /prod/bar
23 | EXPOSE 8001
24 | CMD [ "pnpm", "start" ]
25 |
26 | # docker build . --target foo --tag foo:latest
27 | # docker build . --target bar --tag bar:latest
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 ice breaker
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | Use this section to tell people about which versions of your project are
6 | currently being supported with security updates.
7 |
8 | | Version | Supported |
9 | | ------- | ------------------ |
10 | | 5.1.x | :white_check_mark: |
11 | | 5.0.x | :x: |
12 | | 4.0.x | :white_check_mark: |
13 | | < 4.0 | :x: |
14 |
15 | ## Reporting a Vulnerability
16 |
17 | Use this section to tell people how to report a vulnerability.
18 |
19 | Tell them where to go, how often they can expect to get an update on a
20 | reported vulnerability, what to expect if the vulnerability is accepted or
21 | declined, etc.
22 |
--------------------------------------------------------------------------------
/apps/.gitignore:
--------------------------------------------------------------------------------
1 | .tw-patch
--------------------------------------------------------------------------------
/apps/astro-app/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config'
2 |
3 | // https://astro.build/config
4 | export default defineConfig({})
5 |
--------------------------------------------------------------------------------
/apps/astro-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "",
6 | "author": "",
7 | "license": "ISC",
8 | "keywords": [],
9 | "main": "index.js",
10 | "scripts": {
11 | "dev": "astro dev",
12 | "start": "astro dev",
13 | "build": "astro build",
14 | "preview": "astro preview"
15 | },
16 | "dependencies": {
17 | "astro": "^4.16.7"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/apps/astro-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Example: Allow all bots to scan and index your site.
2 | # Full syntax: https://developers.google.com/search/docs/advanced/robots/create-robots-txt
3 | User-agent: *
4 | Allow: /
--------------------------------------------------------------------------------
/apps/astro-app/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/astro-app/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | // Welcome to Astro! Everything between these triple-dash code fences
3 | // is your "component frontmatter". It never runs in the browser.
4 | console.log('This runs in your terminal, not the browser!');
5 | ---
6 |
8 |
9 |
10 | Hello, World!
11 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/apps/astro-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strictest"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/next-app-router/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/next-app-router/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/apps/next-app-router/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/next-app-router/app/favicon.ico
--------------------------------------------------------------------------------
/apps/next-app-router/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
22 | }
23 |
24 | @layer utilities {
25 | .text-balance {
26 | text-wrap: balance;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/apps/next-app-router/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from 'next'
2 | import { Inter } from 'next/font/google'
3 | import './globals.css'
4 |
5 | const inter = Inter({ subsets: ['latin'] })
6 |
7 | export const metadata: Metadata = {
8 | title: 'Create Next App',
9 | description: 'Generated by create next app',
10 | }
11 |
12 | export default function RootLayout({
13 | children,
14 | }: Readonly<{
15 | children: React.ReactNode
16 | }>) {
17 | return (
18 |
19 | {children}
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/apps/next-app-router/next.config.mjs:
--------------------------------------------------------------------------------
1 | import utwm from 'unplugin-tailwindcss-mangle/webpack'
2 |
3 | /** @type {import('next').NextConfig} */
4 | const nextConfig = {
5 | webpack: (config) => {
6 | config.plugins.push(utwm({
7 | classMapOutput: true,
8 | }))
9 | return config
10 | },
11 | }
12 |
13 | export default nextConfig
14 |
--------------------------------------------------------------------------------
/apps/next-app-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-app-router",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint",
10 | "tw-extract": "tw-patch extract"
11 | },
12 | "dependencies": {
13 | "next": "15.0.1",
14 | "react": "^18",
15 | "react-dom": "^18"
16 | },
17 | "devDependencies": {
18 | "@types/node": "^22.8.1",
19 | "@types/react": "^18.3.12",
20 | "@types/react-dom": "^18",
21 | "eslint": "^9.13.0",
22 | "eslint-config-next": "15.0.1",
23 | "postcss": "^8",
24 | "tailwindcss": "^3.4.1",
25 | "typescript": "^5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/apps/next-app-router/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss-load-config').Config} */
2 | const config = {
3 | plugins: {
4 | tailwindcss: {},
5 | },
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/apps/next-app-router/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/next-app-router/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/next-app-router/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss'
2 |
3 | const config: Config = {
4 | content: [
5 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
6 | './components/**/*.{js,ts,jsx,tsx,mdx}',
7 | './app/**/*.{js,ts,jsx,tsx,mdx}',
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
13 | 'gradient-conic':
14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
15 | },
16 | },
17 | },
18 | plugins: [],
19 | }
20 | export default config
21 |
--------------------------------------------------------------------------------
/apps/next-app-router/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/next-app-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "incremental": true,
4 | "jsx": "preserve",
5 | "lib": ["dom", "dom.iterable", "esnext"],
6 | "module": "esnext",
7 | "moduleResolution": "bundler",
8 | "paths": {
9 | "@/*": ["./*"]
10 | },
11 | "resolveJsonModule": true,
12 | "allowJs": true,
13 | "strict": true,
14 | "noEmit": true,
15 | "esModuleInterop": true,
16 | "isolatedModules": true,
17 | "skipLibCheck": true,
18 | "plugins": [
19 | {
20 | "name": "next"
21 | }
22 | ]
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/apps/next-app/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "next/core-web-vitals"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/next-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/apps/next-app/next.config.js:
--------------------------------------------------------------------------------
1 | // import process from 'node:process'
2 | const process = require('node:process')
3 | const utwm = require('unplugin-tailwindcss-mangle/webpack')
4 | // import utwm from 'unplugin-tailwindcss-mangle'
5 |
6 | /** @type {import('next').NextConfig} */
7 | const nextConfig = {
8 | reactStrictMode: true,
9 | webpack: (config) => {
10 | // console.log(process.env.NODE_ENV)
11 | // if (process.env.NODE_ENV === 'production') {
12 | // config.plugins.push(utwm({
13 | // classMapOutput: true,
14 | // }))
15 | // }
16 | config.plugins.push(utwm({
17 | classMapOutput: true,
18 | }))
19 | return config
20 | },
21 | }
22 |
23 | module.exports = nextConfig
24 |
--------------------------------------------------------------------------------
/apps/next-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint",
10 | "prepare": "tw-patch install",
11 | "tw-extract": "tw-patch extract"
12 | },
13 | "dependencies": {
14 | "@types/node": "22.8.1",
15 | "@types/react": "18.3.12",
16 | "@types/react-dom": "18.3.1",
17 | "autoprefixer": "10.4.20",
18 | "eslint": "9.13.0",
19 | "eslint-config-next": "15.0.1",
20 | "next": "15.0.1",
21 | "postcss": "8.4.47",
22 | "react": "18.3.1",
23 | "react-dom": "18.3.1",
24 | "tailwindcss": "3.4.14",
25 | "typescript": "5.6.3"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/apps/next-app/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import type { AppProps } from 'next/app'
2 | import '@/styles/globals.css'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/apps/next-app/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Head, Html, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/apps/next-app/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | interface Data {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse,
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/apps/next-app/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/next-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/next-app/public/favicon.ico
--------------------------------------------------------------------------------
/apps/next-app/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/next-app/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/next-app/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
22 | }
23 |
--------------------------------------------------------------------------------
/apps/next-app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './pages/**/*.{js,ts,jsx,tsx}',
5 | './components/**/*.{js,ts,jsx,tsx}',
6 | './app/**/*.{js,ts,jsx,tsx}',
7 | ],
8 | theme: {
9 | extend: {
10 | backgroundImage: {
11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
12 | 'gradient-conic':
13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
14 | },
15 | },
16 | },
17 | plugins: [],
18 | corePlugins: {
19 | preflight: false,
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/apps/next-app/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/next-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "incremental": true,
4 | "target": "es5",
5 | "jsx": "preserve",
6 | "lib": ["dom", "dom.iterable", "esnext"],
7 | "module": "esnext",
8 | "moduleResolution": "node",
9 | "paths": {
10 | "@/*": ["./*"]
11 | },
12 | "resolveJsonModule": true,
13 | "allowJs": true,
14 | "strict": true,
15 | "noEmit": true,
16 | "esModuleInterop": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "isolatedModules": true,
19 | "skipLibCheck": true
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------
/apps/nuxt-app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log*
3 | .nuxt
4 | .nitro
5 | .cache
6 | .output
7 | .env
8 | dist
9 | .DS_Store
10 |
--------------------------------------------------------------------------------
/apps/nuxt-app/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
--------------------------------------------------------------------------------
/apps/nuxt-app/assets/css/main.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/apps/nuxt-app/assets/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/nuxt-app/assets/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/nuxt-app/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | // https://nuxt.com/docs/api/configuration/nuxt-config
2 | // import nuxtPlugin from 'unplugin-tailwindcss-mangle/nuxt'
3 |
4 | export default defineNuxtConfig({
5 | css: ['~/assets/css/main.css'],
6 | postcss: {
7 | plugins: {
8 | tailwindcss: {},
9 | autoprefixer: {},
10 | },
11 | },
12 | // https://github.com/nuxt/nuxt/issues/20428
13 | experimental: {
14 | inlineSSRStyles: false,
15 | },
16 | modules: [
17 | // [
18 | // nuxtPlugin,
19 | // {
20 | // classMapOutput: true,
21 | // },
22 | // ],
23 | ],
24 | })
25 |
--------------------------------------------------------------------------------
/apps/nuxt-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nuxt-app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "nuxt build",
7 | "dev": "nuxt dev",
8 | "generate": "nuxt generate",
9 | "preview": "nuxt preview",
10 | "postinstall": "nuxt prepare",
11 | "prepare": "tw-patch install",
12 | "tw-extract": "tw-patch extract"
13 | },
14 | "devDependencies": {
15 | "@types/node": "^22.8.1",
16 | "autoprefixer": "^10.4.20",
17 | "nuxt": "^3.13.2",
18 | "postcss": "^8.4.47",
19 | "tailwindcss": "^3.4.14"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/apps/nuxt-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/nuxt-app/public/favicon.ico
--------------------------------------------------------------------------------
/apps/nuxt-app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./components/**/*.{js,vue,ts}', './layouts/**/*.vue', './pages/**/*.vue', './plugins/**/*.{js,ts}', './nuxt.config.{js,ts}', './app.vue'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/nuxt-app/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/nuxt-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // https://nuxt.com/docs/guide/concepts/typescript
3 | "extends": "./.nuxt/tsconfig.json"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/remix-app/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import('eslint').Linter.Config} */
2 | module.exports = {
3 | extends: ['@remix-run/eslint-config', '@remix-run/eslint-config/node'],
4 | }
5 |
--------------------------------------------------------------------------------
/apps/remix-app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /.cache
4 | /build
5 | /public/build
6 | .env
7 |
--------------------------------------------------------------------------------
/apps/remix-app/app/entry.client.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * By default, Remix will handle hydrating your app on the client for you.
3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
4 | * For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
5 | */
6 |
7 | import { RemixBrowser } from '@remix-run/react'
8 | import { startTransition, StrictMode } from 'react'
9 | import { hydrateRoot } from 'react-dom/client'
10 |
11 | startTransition(() => {
12 | hydrateRoot(
13 | document,
14 |
15 |
16 | ,
17 | )
18 | })
19 |
--------------------------------------------------------------------------------
/apps/remix-app/app/root.tsx:
--------------------------------------------------------------------------------
1 | import type { LinksFunction } from '@remix-run/node'
2 | import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react'
3 | import stylesheet from '~/tailwind.css'
4 |
5 | export const links: LinksFunction = () => [{ rel: 'stylesheet', href: stylesheet }]
6 |
7 | export default function App() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/apps/remix-app/app/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/apps/remix-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "remix-app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "sideEffects": false,
6 | "engines": {
7 | "node": ">=14"
8 | },
9 | "scripts": {
10 | "build": "remix build",
11 | "dev": "remix dev",
12 | "start": "remix-serve build",
13 | "typecheck": "tsc",
14 | "prepare": "tw-patch install",
15 | "tw-extract": "tw-patch extract"
16 | },
17 | "dependencies": {
18 | "@remix-run/node": "^2.13.1",
19 | "@remix-run/react": "^2.13.1",
20 | "@remix-run/serve": "^2.13.1",
21 | "isbot": "^5.1.17",
22 | "react": "^18.3.1",
23 | "react-dom": "^18.3.1"
24 | },
25 | "devDependencies": {
26 | "@remix-run/dev": "^2.13.1",
27 | "@remix-run/eslint-config": "^2.13.1",
28 | "@types/react": "^18.3.12",
29 | "@types/react-dom": "^18.3.1",
30 | "eslint": "^9.13.0",
31 | "tailwindcss": "^3.4.14",
32 | "typescript": "^5.6.3"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/apps/remix-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/remix-app/public/favicon.ico
--------------------------------------------------------------------------------
/apps/remix-app/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | ignoredRouteFiles: ['**/.*'],
4 | // appDirectory: "app",
5 | // assetsBuildDirectory: "public/build",
6 | // serverBuildPath: "build/index.js",
7 | // publicPath: "/build/",
8 | future: {
9 | v2_errorBoundary: true,
10 | v2_meta: true,
11 | v2_normalizeFormMethod: true,
12 | v2_routeConvention: true,
13 | unstable_tailwind: true,
14 | },
15 | // where to register webpack plugin ????
16 | }
17 |
--------------------------------------------------------------------------------
/apps/remix-app/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/apps/remix-app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./app/**/*.{js,jsx,ts,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/remix-app/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/remix-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2019",
4 | "jsx": "react-jsx",
5 | "lib": ["DOM", "DOM.Iterable", "ES2019"],
6 | "baseUrl": ".",
7 | "moduleResolution": "node",
8 | "paths": {
9 | "~/*": ["./app/*"]
10 | },
11 | "resolveJsonModule": true,
12 | "allowJs": true,
13 | "strict": true,
14 | "esModuleInterop": true,
15 | "isolatedModules": true,
16 |
17 | // Remix takes care of building everything in `remix build`.
18 | "noEmit": true,
19 | "forceConsistentCasingInFileNames": true
20 | },
21 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"]
22 | }
23 |
--------------------------------------------------------------------------------
/apps/solid-app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/apps/solid-app/README.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
4 |
5 | This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
6 |
7 | ```bash
8 | $ npm install # or pnpm install or yarn install
9 | ```
10 |
11 | ### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
12 |
13 | ## Available Scripts
14 |
15 | In the project directory, you can run:
16 |
17 | ### `npm dev` or `npm start`
18 |
19 | Runs the app in the development mode.
20 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
21 |
22 | The page will reload if you make edits.
23 |
24 | ### `npm run build`
25 |
26 | Builds the app for production to the `dist` folder.
27 | It correctly bundles Solid in production mode and optimizes the build for the best performance.
28 |
29 | The build is minified and the filenames include the hashes.
30 | Your app is ready to be deployed!
31 |
32 | ## Deployment
33 |
34 | You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)
35 |
--------------------------------------------------------------------------------
/apps/solid-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Solid App
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/apps/solid-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-template-solid",
3 | "version": "0.0.0",
4 | "private": true,
5 | "description": "",
6 | "license": "MIT",
7 | "scripts": {
8 | "start": "vite",
9 | "dev": "vite",
10 | "build": "vite build",
11 | "serve": "vite preview",
12 | "preview": "vite preview",
13 | "prepare": "tw-patch install",
14 | "tw-extract": "tw-patch extract"
15 | },
16 | "dependencies": {
17 | "solid-js": "^1.9.2"
18 | },
19 | "devDependencies": {
20 | "autoprefixer": "^10.4.20",
21 | "postcss": "^8.4.47",
22 | "tailwindcss": "^3.4.14",
23 | "typescript": "^5.6.3",
24 | "vite": "^5.4.9",
25 | "vite-plugin-solid": "^2.10.2"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/apps/solid-app/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/solid-app/src/App.module.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .logo {
6 | animation: logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .link {
23 | color: #b318f0;
24 | }
25 |
26 | @keyframes logo-spin {
27 | from {
28 | transform: rotate(0deg);
29 | }
30 | to {
31 | transform: rotate(360deg);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/solid-app/src/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/solid-app/src/assets/favicon.ico
--------------------------------------------------------------------------------
/apps/solid-app/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | body {
6 | margin: 0;
7 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
8 | 'Droid Sans', 'Helvetica Neue', sans-serif;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | }
12 |
13 | code {
14 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
15 | }
16 |
--------------------------------------------------------------------------------
/apps/solid-app/src/index.tsx:
--------------------------------------------------------------------------------
1 | /* @refresh reload */
2 | import { render } from 'solid-js/web'
3 |
4 | import App from './App'
5 | import './index.css'
6 |
7 | const root = document.getElementById('root')
8 |
9 | if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
10 | throw new Error(
11 | 'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got mispelled?',
12 | )
13 | }
14 |
15 | render(() => , root!)
16 |
--------------------------------------------------------------------------------
/apps/solid-app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/solid-app/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/solid-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "preserve",
5 | "jsxImportSource": "solid-js",
6 | "module": "ESNext",
7 | "moduleResolution": "node",
8 | "types": ["vite/client"],
9 | "strict": true,
10 | "noEmit": true,
11 | "allowSyntheticDefaultImports": true,
12 | "esModuleInterop": true,
13 | "isolatedModules": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/solid-app/vite.config.ts:
--------------------------------------------------------------------------------
1 | import utwm from 'unplugin-tailwindcss-mangle/vite'
2 | import { defineConfig } from 'vite'
3 | import solidPlugin from 'vite-plugin-solid'
4 |
5 | export default defineConfig({
6 | plugins: [
7 | solidPlugin(),
8 | utwm({
9 | classMapOutput: true,
10 | }),
11 | ],
12 | server: {
13 | port: 3000,
14 | },
15 | build: {
16 | target: 'esnext',
17 | },
18 | })
19 |
--------------------------------------------------------------------------------
/apps/vite-lit/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/apps/vite-lit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Lit + TS
8 |
9 |
10 |
11 |
12 |
13 | Vite + Lit
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/apps/vite-lit/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-lit",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "private": true,
6 | "exports": {
7 | ".": "./dist/my-element.es.js"
8 | },
9 | "main": "dist/my-element.es.js",
10 | "types": "types/my-element.d.ts",
11 | "files": [
12 | "dist",
13 | "types"
14 | ],
15 | "scripts": {
16 | "dev": "vite",
17 | "_build": "tsc && vite build",
18 | "prepare": "tw-patch install",
19 | "tw-extract": "tw-patch extract"
20 | },
21 | "dependencies": {
22 | "lit": "^3.2.1"
23 | },
24 | "devDependencies": {
25 | "autoprefixer": "^10.4.20",
26 | "postcss": "^8.4.47",
27 | "tailwindcss": "^3.4.14",
28 | "typescript": "^5.6.3",
29 | "vite": "^5.4.9"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/apps/vite-lit/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-lit/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-lit/src/assets/lit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-lit/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
7 | line-height: 1.5;
8 | font-weight: 400;
9 |
10 | color-scheme: light dark;
11 | color: rgba(255, 255, 255, 0.87);
12 | background-color: #242424;
13 |
14 | font-synthesis: none;
15 | text-rendering: optimizeLegibility;
16 | -webkit-font-smoothing: antialiased;
17 | -moz-osx-font-smoothing: grayscale;
18 | -webkit-text-size-adjust: 100%;
19 | }
20 |
21 | a {
22 | font-weight: 500;
23 | color: #646cff;
24 | text-decoration: inherit;
25 | }
26 | a:hover {
27 | color: #535bf2;
28 | }
29 |
30 | body {
31 | margin: 0;
32 | display: flex;
33 | place-items: center;
34 | min-width: 320px;
35 | min-height: 100vh;
36 | }
37 |
38 | @media (prefers-color-scheme: light) {
39 | :root {
40 | color: #213547;
41 | background-color: #ffffff;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/apps/vite-lit/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/vite-lit/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/vite-lit/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/vite-lit/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
4 | "useDefineForClassFields": false,
5 | "experimentalDecorators": true,
6 | "module": "ESNext",
7 | "moduleResolution": "Node",
8 | "strict": true,
9 | "noFallthroughCasesInSwitch": true,
10 | "noImplicitReturns": true,
11 | "noUnusedLocals": true,
12 | "noUnusedParameters": true,
13 | "declaration": true,
14 | "emitDeclarationOnly": true,
15 | "outDir": "./types",
16 | "allowSyntheticDefaultImports": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "isolatedModules": true,
19 | "skipLibCheck": true
20 | },
21 | "references": [{ "path": "./tsconfig.node.json" }],
22 | "include": ["src/**/*.ts"]
23 | }
24 |
--------------------------------------------------------------------------------
/apps/vite-lit/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/apps/vite-lit/vite.config.ts:
--------------------------------------------------------------------------------
1 | import utwm from 'unplugin-tailwindcss-mangle/vite'
2 | import { defineConfig } from 'vite'
3 | // https://vitejs.dev/config/
4 | export default defineConfig({
5 | build: {
6 | lib: {
7 | entry: 'src/my-element.ts',
8 | formats: ['es'],
9 | },
10 | rollupOptions: {
11 | external: /^lit/,
12 | },
13 | },
14 | plugins: [utwm()],
15 | })
16 |
--------------------------------------------------------------------------------
/apps/vite-react/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/apps/vite-react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/apps/vite-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "private": true,
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview",
10 | "prepare": "tw-patch install",
11 | "tw-extract": "tw-patch extract"
12 | },
13 | "dependencies": {
14 | "@nextui-org/button": "^2.0.38",
15 | "@nextui-org/react": "^2.4.8",
16 | "@nextui-org/system": "^2.2.6",
17 | "@nextui-org/theme": "^2.2.11",
18 | "framer-motion": "^11.11.9",
19 | "react": "^18.3.1",
20 | "react-dom": "^18.3.1",
21 | "react-router-dom": "^6.27.0"
22 | },
23 | "devDependencies": {
24 | "@types/react": "^18.3.12",
25 | "@types/react-dom": "^18.3.1",
26 | "@vitejs/plugin-react": "^4.3.3",
27 | "autoprefixer": "^10.4.20",
28 | "postcss": "^8.4.47",
29 | "tailwindcss": "^3.4.14",
30 | "typescript": "^5.6.3",
31 | "vite": "^5.4.9"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/vite-react/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-react/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import { NextUIProvider } from '@nextui-org/react'
2 | import React from 'react'
3 | import ReactDOM from 'react-dom/client'
4 | import {
5 | createBrowserRouter,
6 | RouterProvider,
7 | } from 'react-router-dom'
8 | import App from './App'
9 | import Next from './next'
10 | import './index.scss'
11 |
12 | const router = createBrowserRouter([
13 | {
14 | path: '/',
15 | element: ,
16 | },
17 | {
18 | path: '/next',
19 | element: ,
20 | },
21 | ])
22 |
23 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
24 |
25 |
26 |
27 |
28 | ,
29 | )
30 |
--------------------------------------------------------------------------------
/apps/vite-react/src/next.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@nextui-org/button'
2 |
3 | export default function () {
4 | return (
5 |
6 |
7 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/apps/vite-react/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from 'clsx'
2 | import { twMerge } from 'tailwind-merge'
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-react/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/vite-react/tailwind.config.js:
--------------------------------------------------------------------------------
1 | import { nextui } from '@nextui-org/react'
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | export default {
5 | content: [
6 | './index.html',
7 | './src/**/*.{js,ts,jsx,tsx}',
8 | './node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}',
9 | ],
10 | theme: {
11 | extend: {},
12 | },
13 | darkMode: 'class',
14 | plugins: [nextui()],
15 | corePlugins: {
16 | preflight: false,
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/apps/vite-react/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | mangle: {
5 | preserveFunction: ['twMerge', 'cn'],
6 | },
7 | })
8 |
--------------------------------------------------------------------------------
/apps/vite-react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "react-jsx",
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "useDefineForClassFields": true,
7 | "module": "ESNext",
8 | "moduleResolution": "Node",
9 | "resolveJsonModule": true,
10 | "allowJs": false,
11 | "strict": true,
12 | "noEmit": true,
13 | "allowSyntheticDefaultImports": true,
14 | "esModuleInterop": false,
15 | "forceConsistentCasingInFileNames": true,
16 | "isolatedModules": true,
17 | "skipLibCheck": true
18 | },
19 | "references": [{ "path": "./tsconfig.node.json" }],
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/apps/vite-react/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "target": "ESNext",
5 | "module": "ESNext",
6 | "moduleResolution": "Bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/apps/vite-react/vite.config.ts:
--------------------------------------------------------------------------------
1 | import react from '@vitejs/plugin-react'
2 | import { register } from 'tsx/esm/api'
3 | import { defineConfig } from 'vite'
4 |
5 | register()
6 | const { default: utwm } = await import('unplugin-tailwindcss-mangle/vite')
7 |
8 | export default defineConfig({
9 | plugins: [
10 | react(),
11 | utwm({
12 | classMapOutput: true,
13 | }),
14 | ],
15 | css: {
16 | preprocessorOptions: {
17 | scss: {
18 | silenceDeprecations: ['legacy-js-api'],
19 | },
20 | },
21 | },
22 | })
23 |
--------------------------------------------------------------------------------
/apps/vite-svelte/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/apps/vite-svelte/.tw-patch/tw-class-list.json:
--------------------------------------------------------------------------------
1 | [
2 | "drop-shadow",
3 | "filter",
4 | "flex",
5 | "justify-between",
6 | "text-[40px]",
7 | "text-[red]",
8 | "transition"
9 | ]
10 |
--------------------------------------------------------------------------------
/apps/vite-svelte/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["svelte.svelte-vscode"]
3 | }
4 |
--------------------------------------------------------------------------------
/apps/vite-svelte/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Svelte + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/apps/vite-svelte/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-svelte",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "private": true,
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "check": "svelte-check --tsconfig ./tsconfig.json",
11 | "prepare": "tw-patch install",
12 | "tw-extract": "tw-patch extract"
13 | },
14 | "devDependencies": {
15 | "@sveltejs/vite-plugin-svelte": "^4.0.0",
16 | "@tsconfig/svelte": "^5.0.4",
17 | "autoprefixer": "^10.4.20",
18 | "postcss": "^8.4.47",
19 | "svelte": "^5.0.5",
20 | "svelte-check": "^4.0.5",
21 | "tailwindcss": "^3.4.14",
22 | "tslib": "^2.8.0",
23 | "typescript": "^5.6.3",
24 | "vite": "^5.4.9"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/apps/vite-svelte/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-svelte/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-svelte/src/App.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
16 | Vite + Svelte
17 |
18 |
19 |
20 |
21 |
22 |
23 | Check out SvelteKit, the official Svelte app framework powered by Vite!
24 |
25 |
26 |
27 | Click on the Vite and Svelte logos to learn more
28 |
29 |
30 |
31 |
48 |
--------------------------------------------------------------------------------
/apps/vite-svelte/src/lib/Counter.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/apps/vite-svelte/src/main.ts:
--------------------------------------------------------------------------------
1 | import App from './App.svelte'
2 | import './app.css'
3 |
4 | const app = new App({
5 | target: document.getElementById('app'),
6 | })
7 |
8 | export default app
9 |
--------------------------------------------------------------------------------
/apps/vite-svelte/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/apps/vite-svelte/svelte.config.js:
--------------------------------------------------------------------------------
1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
2 |
3 | export default {
4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
5 | // for more information about preprocessors
6 | preprocess: vitePreprocess(),
7 | }
8 |
--------------------------------------------------------------------------------
/apps/vite-svelte/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./index.html', './src/**/*.{html,js,svelte,ts}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/vite-svelte/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/vite-svelte/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/svelte/tsconfig.json",
3 | "compilerOptions": {
4 | "target": "ESNext",
5 | "useDefineForClassFields": true,
6 | "module": "ESNext",
7 | "resolveJsonModule": true,
8 | /**
9 | * Typecheck JS in `.svelte` and `.js` files by default.
10 | * Disable checkJs if you'd like to use dynamic types in JS.
11 | * Note that setting allowJs false does not prevent the use
12 | * of JS in `.svelte` files.
13 | */
14 | "allowJs": true,
15 | "checkJs": true,
16 | "isolatedModules": true
17 | },
18 | "references": [{ "path": "./tsconfig.node.json" }],
19 | "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
20 | }
21 |
--------------------------------------------------------------------------------
/apps/vite-svelte/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node"
6 | },
7 | "include": ["vite.config.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/apps/vite-svelte/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { svelte } from '@sveltejs/vite-plugin-svelte'
2 | import utwm from 'unplugin-tailwindcss-mangle/vite'
3 | import { defineConfig } from 'vite'
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [
7 | svelte(),
8 | utwm({
9 | classMapOutput: true,
10 | }),
11 | ],
12 | })
13 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-vanilla",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "private": true,
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview",
10 | "prepare": "tw-patch install",
11 | "tw-extract": "tw-patch extract"
12 | },
13 | "devDependencies": {
14 | "autoprefixer": "^10.4.20",
15 | "postcss": "^8.4.47",
16 | "tailwindcss": "^3.4.14",
17 | "typescript": "^5.6.3",
18 | "vite": "^5.4.9"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/src/counter.ts:
--------------------------------------------------------------------------------
1 | export function setupCounter(element: HTMLButtonElement) {
2 | let counter = 0
3 | const setCounter = (count: number) => {
4 | counter = count
5 | element.innerHTML = `count is ${counter}
`
6 | }
7 | element.addEventListener('click', () => setCounter(counter + 1))
8 | setCounter(0)
9 | }
10 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/src/typescript.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["ESNext", "DOM"],
5 | "useDefineForClassFields": true,
6 | "module": "ESNext",
7 | "moduleResolution": "Node",
8 | "resolveJsonModule": true,
9 | "strict": true,
10 | "noImplicitReturns": true,
11 | "noUnusedLocals": true,
12 | "noUnusedParameters": true,
13 | "noEmit": true,
14 | "esModuleInterop": true,
15 | "isolatedModules": true,
16 | "skipLibCheck": true
17 | },
18 | "include": ["src"]
19 | }
20 |
--------------------------------------------------------------------------------
/apps/vite-vanilla/vite.config.ts:
--------------------------------------------------------------------------------
1 | import utwm from 'unplugin-tailwindcss-mangle/vite'
2 | import { defineConfig } from 'vite'
3 | // https://vitejs.dev/config/
4 | export default defineConfig({
5 | plugins: [
6 | utwm({
7 | classMapOutput: true,
8 | }),
9 | ],
10 | })
11 |
--------------------------------------------------------------------------------
/apps/vite-vue/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/apps/vite-vue/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3 | }
4 |
--------------------------------------------------------------------------------
/apps/vite-vue/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/apps/vite-vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-vue",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "private": true,
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "prepare": "tw-patch install",
11 | "tw-extract": "tw-patch extract"
12 | },
13 | "dependencies": {
14 | "vue": "^3.5.12"
15 | },
16 | "devDependencies": {
17 | "@vitejs/plugin-vue": "^5.1.4",
18 | "autoprefixer": "^10.4.20",
19 | "postcss": "^8.4.47",
20 | "sass": "^1.80.3",
21 | "tailwindcss": "^3.4.14",
22 | "typescript": "^5.6.3",
23 | "vite": "^5.4.9",
24 | "vue-tsc": "^2.1.6"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/apps/vite-vue/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/vite-vue/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-vue/src/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/vite-vue/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | {{ msg }}
11 |
12 |
13 |
14 |
15 | Edit
16 | components/HelloWorld.vue
to test HMR
17 |
18 |
19 |
20 |
21 | Check out
22 | create-vue, the official Vue + Vite starter
25 |
26 |
27 | Install
28 | Volar
29 | in your IDE for a better DX
30 |
31 | Click on the Vite and Vue logos to learn more
32 |
33 |
34 |
39 |
--------------------------------------------------------------------------------
/apps/vite-vue/src/index.scss:
--------------------------------------------------------------------------------
1 | .red {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/apps/vite-vue/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import './style.css'
4 | import './index.scss'
5 |
6 | console.log('bg-[#929292]')
7 |
8 | createApp(App).mount('#app')
9 |
--------------------------------------------------------------------------------
/apps/vite-vue/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/vite-vue/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | corePlugins: {
9 | preflight: false,
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/apps/vite-vue/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | mangle: {
5 | preserveFunction: ['twMerge'],
6 | },
7 | })
8 |
--------------------------------------------------------------------------------
/apps/vite-vue/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "preserve",
5 | "lib": ["ESNext", "DOM"],
6 | "useDefineForClassFields": true,
7 | "module": "ESNext",
8 | "moduleResolution": "Node",
9 | "resolveJsonModule": true,
10 | "strict": true,
11 | "noEmit": true,
12 | "esModuleInterop": true,
13 | "isolatedModules": true,
14 | "skipLibCheck": true
15 | },
16 | "references": [{ "path": "./tsconfig.node.json" }],
17 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
18 | }
19 |
--------------------------------------------------------------------------------
/apps/vite-vue/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "target": "ESNext",
5 | "module": "ESNext",
6 | "moduleResolution": "Bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/apps/vite-vue/vite.config.ts:
--------------------------------------------------------------------------------
1 | import vue from '@vitejs/plugin-vue'
2 | import { register } from 'tsx/esm/api'
3 | import { defineConfig } from 'vite'
4 |
5 | register()
6 | const { default: utwm } = await import('unplugin-tailwindcss-mangle/vite')
7 | // https://vitejs.dev/config/
8 | export default defineConfig({
9 | plugins: [
10 | vue(),
11 | utwm({
12 | classMapOutput: true,
13 | }),
14 | ],
15 | css: {
16 | preprocessorOptions: {
17 | scss: {
18 | silenceDeprecations: ['legacy-js-api'],
19 | },
20 | },
21 | },
22 | })
23 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 | not ie 11
5 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset',
4 | ],
5 | }
6 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack5-vue3",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "preview": "vite preview",
9 | "lint": "vue-cli-service lint",
10 | "prepare": "tw-patch install",
11 | "tw-extract": "tw-patch extract"
12 | },
13 | "dependencies": {
14 | "core-js": "^3.38.1",
15 | "vue": "^3.5.12",
16 | "vue-router": "^4.4.5"
17 | },
18 | "devDependencies": {
19 | "@typescript-eslint/eslint-plugin": "^8.11.0",
20 | "@typescript-eslint/parser": "^8.11.0",
21 | "@vue/cli-plugin-babel": "~5.0.8",
22 | "@vue/cli-plugin-eslint": "~5.0.8",
23 | "@vue/cli-plugin-router": "~5.0.8",
24 | "@vue/cli-plugin-typescript": "~5.0.8",
25 | "@vue/cli-service": "~5.0.8",
26 | "@vue/eslint-config-standard": "^8.0.1",
27 | "@vue/eslint-config-typescript": "^14.1.2",
28 | "autoprefixer": "^10.4.20",
29 | "eslint": "^9.13.0",
30 | "eslint-plugin-import": "^2.31.0",
31 | "eslint-plugin-node": "^11.1.0",
32 | "eslint-plugin-promise": "^7.1.0",
33 | "eslint-plugin-vue": "^9.29.1",
34 | "postcss": "^8.4.47",
35 | "sass": "^1.80.3",
36 | "sass-loader": "^16.0.2",
37 | "tailwindcss": "^3.4.14",
38 | "typescript": "~5.6.3"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/webpack5-vue3/public/favicon.ico
--------------------------------------------------------------------------------
/apps/webpack5-vue3/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/apps/webpack5-vue3/src/assets/logo.png
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | HelloWorld
4 |
5 |
6 |
7 |
17 |
18 |
19 |
37 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 |
5 | createApp(App).use(router).mount('#app')
6 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import { createRouter, createWebHistory } from 'vue-router'
3 | import HomeView from '../views/HomeView.vue'
4 |
5 | const routes: Array = [
6 | {
7 | path: '/',
8 | name: 'home',
9 | component: HomeView,
10 | },
11 | {
12 | path: '/about',
13 | name: 'about',
14 | // route level code-splitting
15 | // this generates a separate chunk (about.[hash].js) for this route
16 | // which is lazy-loaded when the route is visited.
17 | component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue'),
18 | },
19 | ]
20 |
21 | const router = createRouter({
22 | history: createWebHistory(process.env.BASE_URL),
23 | routes,
24 | })
25 |
26 | export default router
27 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/views/AboutView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./src/**/*.{js,ts,jsx,tsx,vue}'],
4 | darkMode: 'class',
5 | theme: {
6 | extend: {},
7 | },
8 | plugins: [],
9 | corePlugins: {
10 | preflight: false,
11 | },
12 | }
13 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "jsx": "preserve",
5 | "lib": [
6 | "esnext",
7 | "dom",
8 | "dom.iterable",
9 | "scripthost"
10 | ],
11 | "useDefineForClassFields": true,
12 | "baseUrl": ".",
13 | "module": "esnext",
14 | "moduleResolution": "node",
15 | "paths": {
16 | "@/*": [
17 | "src/*"
18 | ]
19 | },
20 | "types": [
21 | "webpack-env"
22 | ],
23 | "strict": true,
24 | "sourceMap": true,
25 | "allowSyntheticDefaultImports": true,
26 | "esModuleInterop": true,
27 | "forceConsistentCasingInFileNames": true,
28 | "skipLibCheck": true
29 | },
30 | "include": [
31 | "src/**/*.ts",
32 | "src/**/*.tsx",
33 | "src/**/*.vue",
34 | "tests/**/*.ts",
35 | "tests/**/*.tsx"
36 | ],
37 | "exclude": [
38 | "node_modules"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/apps/webpack5-vue3/vue.config.js:
--------------------------------------------------------------------------------
1 | const { defineConfig } = require('@vue/cli-service')
2 | const utwm = require('unplugin-tailwindcss-mangle/webpack')
3 |
4 | module.exports = defineConfig({
5 | transpileDependencies: true,
6 | // configureWebpack: (config) => {
7 | // config.plugins.push(utwm({
8 | // classMapOutput: true,
9 | // }))
10 | // },
11 |
12 | })
13 |
--------------------------------------------------------------------------------
/assets/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assets",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "",
6 | "author": "",
7 | "license": "ISC",
8 | "keywords": [],
9 | "main": "index.js",
10 | "scripts": {
11 | "prepare": "tw-patch install",
12 | "extract": "tw-patch extract"
13 | },
14 | "dependencies": {
15 | "tailwindcss-patch": "^5.0.1",
16 | "unplugin-tailwindcss-mangle": "^4.0.1"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/commitlint.config.ts:
--------------------------------------------------------------------------------
1 | import type { UserConfig } from '@commitlint/types'
2 | // import { RuleConfigSeverity } from '@commitlint/types'
3 |
4 | export default {
5 | extends: ['@commitlint/config-conventional'],
6 | }
7 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import { icebreaker } from '@icebreakers/eslint-config'
2 |
3 | export default icebreaker(
4 | {
5 | ignores: ['**/fixtures/**'],
6 | },
7 | )
8 |
--------------------------------------------------------------------------------
/lint-staged.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | '*.{js,jsx,mjs,ts,tsx,mts,vue}': [
3 | 'eslint --fix',
4 | ],
5 | '*.{json,md,mdx,css,html,yml,yaml,scss}': [
6 | // 'prettier --with-node-modules --ignore-path .prettierignore --write',
7 | 'eslint --fix',
8 | ],
9 | // for rust
10 | // '*.rs': ['cargo fmt --'],
11 | }
12 |
--------------------------------------------------------------------------------
/packages/config/src/config.ts:
--------------------------------------------------------------------------------
1 | import type { UserConfig } from './types'
2 | import { createDefineConfig, loadConfig } from 'c12'
3 | import fs from 'fs-extra'
4 | import path from 'pathe'
5 | import { CONFIG_NAME } from './constants'
6 | import { getDefaultUserConfig } from './defaults'
7 |
8 | export function getConfig(cwd?: string) {
9 | return loadConfig({
10 | name: CONFIG_NAME,
11 | defaults: {
12 | ...getDefaultUserConfig(),
13 | },
14 | cwd,
15 | })
16 | }
17 |
18 | export const defineConfig = createDefineConfig()
19 |
20 | export function initConfig(cwd: string) {
21 | return fs.outputFile(
22 | path.resolve(cwd, `${CONFIG_NAME}.config.ts`),
23 | `import { defineConfig } from 'tailwindcss-patch'
24 |
25 | export default defineConfig({})
26 | `,
27 | 'utf8',
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/packages/config/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const CONFIG_NAME = 'tailwindcss-mangle'
2 |
--------------------------------------------------------------------------------
/packages/config/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './config'
2 | export * from './constants'
3 | export * from './defaults'
4 | export * from './types'
5 |
--------------------------------------------------------------------------------
/packages/config/test/__snapshots__/config.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`config > init config 1`] = `
4 | "import { defineConfig } from 'tailwindcss-patch'
5 |
6 | export default defineConfig({})
7 | "
8 | `;
9 |
--------------------------------------------------------------------------------
/packages/config/test/__snapshots__/defaults.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`defaults > getDefaultPatchConfig 1`] = `
4 | {
5 | "output": {
6 | "filename": ".tw-patch/tw-class-list.json",
7 | "loose": true,
8 | "removeUniversalSelector": true,
9 | },
10 | "tailwindcss": {},
11 | }
12 | `;
13 |
14 | exports[`defaults > getDefaultUserConfig 1`] = `
15 | {
16 | "mangle": {
17 | "classListPath": ".tw-patch/tw-class-list.json",
18 | "classMapOutput": {
19 | "enable": false,
20 | "filename": ".tw-patch/tw-map-list.json",
21 | "loose": true,
22 | },
23 | "disabled": false,
24 | "exclude": [],
25 | "include": [
26 | /\\\\\\.\\(html\\|js\\|ts\\|jsx\\|tsx\\|vue\\|svelte\\|astro\\|elm\\|php\\|phtml\\|mdx\\|md\\)\\(\\?:\\$\\|\\\\\\?\\)/,
27 | /\\\\\\.\\(css\\|less\\|sass\\|scss\\|styl\\|stylus\\|pcss\\|postcss\\|sss\\)\\(\\?:\\$\\|\\\\\\?\\)/,
28 | ],
29 | "mangleClassFilter": [Function],
30 | "preserveFunction": [],
31 | },
32 | "patch": {
33 | "output": {
34 | "filename": ".tw-patch/tw-class-list.json",
35 | "loose": true,
36 | "removeUniversalSelector": true,
37 | },
38 | "tailwindcss": {},
39 | },
40 | }
41 | `;
42 |
--------------------------------------------------------------------------------
/packages/config/test/__snapshots__/index.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`config > 2.mangle-options 1`] = `
4 | {
5 | "mangle": {
6 | "classGenerator": {
7 | "log": true,
8 | },
9 | "classListPath": "zzzzz.json",
10 | "classMapOutput": {
11 | "enable": true,
12 | "filename": "ffff.json",
13 | "loose": false,
14 | },
15 | "disabled": false,
16 | "exclude": [],
17 | "include": [
18 | /\\\\\\.\\(html\\|js\\|ts\\|jsx\\|tsx\\|vue\\|svelte\\|astro\\|elm\\|php\\|phtml\\|mdx\\|md\\)\\(\\?:\\$\\|\\\\\\?\\)/,
19 | /\\\\\\.\\(css\\|less\\|sass\\|scss\\|styl\\|stylus\\|pcss\\|postcss\\|sss\\)\\(\\?:\\$\\|\\\\\\?\\)/,
20 | ],
21 | "mangleClassFilter": [Function],
22 | "preserveFunction": [],
23 | },
24 | "patch": {
25 | "output": {
26 | "filename": "xxx/yyy/zzz.json",
27 | "loose": false,
28 | "removeUniversalSelector": false,
29 | },
30 | "tailwindcss": {
31 | "cwd": "aaa/bbb/cc",
32 | },
33 | },
34 | }
35 | `;
36 |
--------------------------------------------------------------------------------
/packages/config/test/config.test.ts:
--------------------------------------------------------------------------------
1 | import { initConfig } from '@/config'
2 | import fs from 'fs-extra'
3 | import path from 'pathe'
4 |
5 | describe('config', () => {
6 | it('init config', async () => {
7 | const cwd = path.resolve(__dirname, './fixtures/config/initConfig')
8 | await initConfig(cwd)
9 | const dest = path.resolve(cwd, 'tailwindcss-mangle.config.ts')
10 | expect(await fs.readFile(dest, 'utf8')).toMatchSnapshot()
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/packages/config/test/defaults.test.ts:
--------------------------------------------------------------------------------
1 | import { getDefaultPatchConfig, getDefaultUserConfig } from '@/defaults'
2 | import { createFilter } from '@rollup/pluginutils'
3 | import { omit } from 'lodash-es'
4 |
5 | function omitCwdPath(o: any) {
6 | return omit(o, ['tailwindcss.cwd', 'patch.tailwindcss.cwd'])
7 | }
8 |
9 | describe('defaults', () => {
10 | it('getDefaultPatchConfig', () => {
11 | expect(omitCwdPath(getDefaultPatchConfig())).toMatchSnapshot()
12 | })
13 |
14 | it('getDefaultUserConfig', () => {
15 | expect(omitCwdPath(getDefaultUserConfig())).toMatchSnapshot()
16 | })
17 | })
18 |
19 | describe('createFilter', () => {
20 | it('case 0', () => {
21 | const config = getDefaultUserConfig()
22 | const filter = createFilter(config.mangle?.include, config.mangle?.exclude)
23 | expect(filter('xx/yy.js?a=1')).toBe(true)
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/packages/config/test/fixtures/config/0.default/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/config/test/fixtures/config/1.change-options/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | patch: {
5 | output: {
6 | filename: 'xxx/yyy/zzz.json',
7 | loose: false,
8 | removeUniversalSelector: false,
9 | },
10 | tailwindcss: {
11 | cwd: 'aaa/bbb/cc',
12 | },
13 | },
14 | })
15 |
--------------------------------------------------------------------------------
/packages/config/test/fixtures/config/2.mangle-options/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | patch: {
5 | output: {
6 | filename: 'xxx/yyy/zzz.json',
7 | loose: false,
8 | removeUniversalSelector: false,
9 | },
10 | tailwindcss: {
11 | cwd: 'aaa/bbb/cc',
12 | },
13 | },
14 | mangle: {
15 | mangleClassFilter(className) {
16 | return true
17 | },
18 | classListPath: 'zzzzz.json',
19 | classGenerator: {
20 | log: true,
21 | },
22 | disabled: false,
23 | classMapOutput: {
24 | enable: true,
25 | loose: false,
26 | filename: 'ffff.json',
27 | },
28 | },
29 | })
30 |
--------------------------------------------------------------------------------
/packages/config/test/fixtures/config/initConfig/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/config/test/utils.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 |
3 | export const fixturesRoot = path.resolve(__dirname, './fixtures')
4 |
--------------------------------------------------------------------------------
/packages/config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "@/*": [
7 | "src/*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "src",
13 | "test"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/config/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: [
5 | 'src/index.ts',
6 | ], // , 'src/cli.ts'],
7 | shims: true,
8 | format: ['cjs', 'esm'],
9 | clean: true,
10 | dts: true,
11 | // cjsInterop: true,
12 | // splitting: true,
13 | })
14 |
--------------------------------------------------------------------------------
/packages/config/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 | import { defineProject } from 'vitest/config'
3 |
4 | export default defineProject({
5 | test: {
6 | alias: [
7 | {
8 | find: '@',
9 | replacement: path.resolve(__dirname, './src'),
10 | },
11 | ],
12 | globals: true,
13 | testTimeout: 60_000,
14 | },
15 | })
16 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 | # @tailwindcss-mangle/core
2 |
3 | The core of tailwindcss-mangle
4 |
5 | ## Usage
6 |
7 | // TODO
8 |
--------------------------------------------------------------------------------
/packages/core/src/babel/index.ts:
--------------------------------------------------------------------------------
1 | import _babelTraverse from '@babel/traverse'
2 |
3 | export { parse, parseExpression } from '@babel/parser'
4 |
5 | function _interopDefaultCompat(e: any) {
6 | return e && typeof e === 'object' && 'default' in e ? e.default : e
7 | }
8 |
9 | export const traverse = _interopDefaultCompat(_babelTraverse) as typeof _babelTraverse
10 |
--------------------------------------------------------------------------------
/packages/core/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const ignoreIdentifier = 'twIgnore'
2 |
--------------------------------------------------------------------------------
/packages/core/src/css/index.ts:
--------------------------------------------------------------------------------
1 | import type { ICssHandlerOptions, IHandlerTransformResult } from '../types'
2 | import postcss from 'postcss'
3 | import { transformSelectorPostcssPlugin } from './plugins'
4 |
5 | export async function cssHandler(rawSource: string, options: ICssHandlerOptions): Promise {
6 | const acceptedPlugins = [transformSelectorPostcssPlugin(options)]
7 | const { id } = options
8 | try {
9 | const { css: code, map } = await postcss(acceptedPlugins).process(rawSource, {
10 | from: id,
11 | to: id,
12 | })
13 | return {
14 | code,
15 | // @ts-ignore
16 | map,
17 | }
18 | }
19 | catch (_error) {
20 | return {
21 | code: rawSource,
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/core/src/env.ts:
--------------------------------------------------------------------------------
1 | import process from 'node:process'
2 |
3 | export const isProd = () => process.env.NODE_ENV === 'production'
4 | export const isDev = () => process.env.NODE_ENV === 'development'
5 |
--------------------------------------------------------------------------------
/packages/core/src/html/index.ts:
--------------------------------------------------------------------------------
1 | import type { IHandlerTransformResult, IHtmlHandlerOptions } from '../types'
2 | import { Parser } from 'htmlparser2'
3 | import MagicString from 'magic-string'
4 | import { makeRegex, splitCode } from '../shared'
5 |
6 | export function htmlHandler(raw: string | MagicString, options: IHtmlHandlerOptions): IHandlerTransformResult {
7 | const { ctx, id } = options
8 | const { replaceMap, classGenerator } = ctx
9 | const ms: MagicString = typeof raw === 'string' ? new MagicString(raw) : raw
10 | const parser = new Parser({
11 | onattribute(name, value) {
12 | if (name === 'class') {
13 | let needUpdate = false
14 | const arr = splitCode(value, {
15 | splitQuote: false,
16 | })
17 | let rawValue = value
18 | for (const v of arr) {
19 | if (replaceMap.has(v)) {
20 | const gen = classGenerator.generateClassName(v)
21 | rawValue = rawValue.replace(makeRegex(v), gen.name)
22 | ctx.addToUsedBy(v, id)
23 | needUpdate = true
24 | }
25 | }
26 | needUpdate && ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue)
27 | }
28 | },
29 | })
30 | parser.write(ms.original)
31 | parser.end()
32 | return {
33 | code: ms.toString(),
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './css'
2 | export * from './ctx'
3 | export * from './html'
4 | export * from './js'
5 | export { ClassGenerator } from './shared'
6 | export * from './types'
7 |
--------------------------------------------------------------------------------
/packages/core/src/js/utils.ts:
--------------------------------------------------------------------------------
1 | import type babel from '@babel/core'
2 | // const t = babel.types
3 | export function getStringLiteralCalleeName(path: babel.NodePath) {
4 | if (path.parentPath.isCallExpression()) {
5 | const callee = path.parentPath.get('callee')
6 | if (callee.isIdentifier()) {
7 | return callee.node.name
8 | }
9 | }
10 | }
11 |
12 | export function getTemplateElementCalleeName(path: babel.NodePath) {
13 | if (path.parentPath.isTemplateLiteral()) {
14 | const pp = path.parentPath
15 | if (pp.parentPath.isCallExpression()) {
16 | const callee = pp.parentPath.get('callee')
17 | if (callee.isIdentifier()) {
18 | return callee.node.name
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/core/src/math.ts:
--------------------------------------------------------------------------------
1 | export function between(x: number | null | undefined, min: number, max: number, included: boolean = false) {
2 | if (typeof x !== 'number') {
3 | return false
4 | }
5 | return included ? x >= min && x <= max : x > min && x < max
6 | }
7 |
--------------------------------------------------------------------------------
/packages/core/src/shared.ts:
--------------------------------------------------------------------------------
1 | export * from '@tailwindcss-mangle/shared'
2 |
--------------------------------------------------------------------------------
/packages/core/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { TransformResult } from 'unplugin'
2 | import type { Context } from './ctx'
3 |
4 | export interface IClassGeneratorContextItem {
5 | name: string
6 | usedBy: string[]
7 | }
8 |
9 | export interface IClassGeneratorOptions {
10 | reserveClassName?: (string | RegExp)[]
11 | customGenerate?: (original: string, opts: IClassGeneratorOptions, context: Record) => string | undefined
12 | log?: boolean
13 | exclude?: (string | RegExp)[]
14 | include?: (string | RegExp)[]
15 | ignoreClass?: (string | RegExp)[]
16 | classPrefix?: string
17 | }
18 |
19 | export interface IHandler {
20 | (code: string, options: IHandlerOptions): IHandlerTransformResult
21 | }
22 |
23 | export type IHandlerTransformResult = Exclude
24 |
25 | export interface IHandlerOptions {
26 | ctx: Context
27 | id?: string
28 | }
29 |
30 | export interface IHtmlHandlerOptions extends IHandlerOptions {
31 |
32 | }
33 |
34 | export interface IJsHandlerOptions extends IHandlerOptions {
35 | splitQuote?: boolean
36 | }
37 |
38 | export interface ICssHandlerOptions extends IHandlerOptions {
39 | ignoreVueScoped?: boolean
40 | }
41 |
--------------------------------------------------------------------------------
/packages/core/test/__snapshots__/index.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`common usage > hello-world 1`] = `
4 | ".text-3xl {
5 | font-size: 1.875rem;
6 | line-height: 2.25rem
7 | }
8 | .font-bold {
9 | font-weight: 700
10 | }
11 | .underline {
12 | text-decoration-line: underline
13 | }"
14 | `;
15 |
16 | exports[`common usage > hello-world with js 1`] = `
17 | ".bg-\\[\\#123456\\] {
18 | --tw-bg-opacity: 1;
19 | background-color: rgb(18 52 86 / var(--tw-bg-opacity, 1))
20 | }
21 | .text-3xl {
22 | font-size: 1.875rem;
23 | line-height: 2.25rem
24 | }
25 | .font-bold {
26 | font-weight: 700
27 | }
28 | .underline {
29 | text-decoration-line: underline
30 | }"
31 | `;
32 |
--------------------------------------------------------------------------------
/packages/core/test/exports.test.ts:
--------------------------------------------------------------------------------
1 | import { ClassGenerator, cssHandler, handleValue, htmlHandler, jsHandler } from '@/index'
2 |
3 | describe('exports', () => {
4 | it('exports should be defined', () => {
5 | for (const x of [ClassGenerator, cssHandler, handleValue, htmlHandler, jsHandler]) {
6 | expect(x).toBeDefined()
7 | }
8 | })
9 | })
10 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/comment-ignore.js:
--------------------------------------------------------------------------------
1 | const clipPath = [`circle()`]
2 |
3 | document.documentElement.animate(
4 | {
5 | clipPath
6 | },
7 | {
8 | duration: 500,
9 | easing: 'ease-out',
10 | pseudoElement: '::view-transition-new(root)'
11 | }
12 | )
13 |
14 | document.documentElement.animate(
15 | {
16 | clipPath
17 | },
18 | {
19 | duration: 500,
20 | easing: /* tw-mangle ignore */ 'ease-out',
21 | pseudoElement: '::view-transition-new(root)'
22 | }
23 | )
24 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/hello-world.css:
--------------------------------------------------------------------------------
1 | .text-3xl {
2 | font-size: 1.875rem;
3 | line-height: 2.25rem;
4 | }
5 | .font-bold {
6 | font-weight: 700;
7 | }
8 | .underline {
9 | text-decoration-line: underline;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/hello-world.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Hello world!
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/hello-world.js:
--------------------------------------------------------------------------------
1 | const el = document.getElementById('#app')
2 | el && el.classList.add('bg-[#123456]')
3 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fixtures",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "prepare": "tw-patch install",
8 | "tw-extract": "tw-patch extract"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "tailwindcss-patch": "workspace:^"
15 | }
16 | }
--------------------------------------------------------------------------------
/packages/core/test/fixtures/preserve-fn-case0.js:
--------------------------------------------------------------------------------
1 | import { clsx } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
8 | cn('w-10 h-10 bg-red-500 and bg-red-500/50')
9 |
10 | cn(`w-2 h-2 bg-red-600 and bg-red-600/50`)
11 |
12 | twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')
--------------------------------------------------------------------------------
/packages/core/test/fixtures/preserve-fn-case0.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from 'clsx'
2 | import { twMerge } from 'tailwind-merge'
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
8 | cn('w-10 h-10 bg-red-500 and bg-red-500/50')
9 |
10 | cn(`w-2 h-2 bg-red-600 and bg-red-600/50`)
11 |
12 | twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')
13 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/preserve-fn-case2.json:
--------------------------------------------------------------------------------
1 | [
2 | "bg-[#B91C1C]",
3 | "bg-red-100",
4 | "drop-shadow",
5 | "filter",
6 | "flex",
7 | "flex-col",
8 | "hover:bg-red-100",
9 | "hover:bg-red-800",
10 | "items-center",
11 | "justify-between",
12 | "lg:dark:bg-red-100",
13 | "min-h-screen",
14 | "p-24",
15 | "p-3",
16 | "px-2",
17 | "py-1",
18 | "transition"
19 | ]
--------------------------------------------------------------------------------
/packages/core/test/fixtures/preserve-fn-case2.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
28 |
29 |
45 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/prod/0.js:
--------------------------------------------------------------------------------
1 | // Unterminated string constant
2 | if (isSvg) {
3 | let source = serializeString(svgNode);
4 | // add xml declaration
5 | source = '\r\n' + source;
6 | // convert svg source to URI data scheme.
7 | url = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
8 | saveAs(url, "graph.svg");
9 | onAlreadySerialized();
10 | return;
11 | }
--------------------------------------------------------------------------------
/packages/core/test/fixtures/prod/1.js:
--------------------------------------------------------------------------------
1 | // Missing semicolon.
2 | if (typeof parent === 'string') {
3 | parent = d.querySelectorAll(config.parent);
4 | if (parent.length > 1) {
5 | console.warn('WARNING: the given `parent` query(' + config.parent + ') matched more than one element, the first one will be used');
6 | }
7 | if (parent.length === 0) {
8 | throw 'ERROR: the given `parent` doesn\'t exists!';
9 | }
10 | parent = parent[0];
11 | }
--------------------------------------------------------------------------------
/packages/core/test/fixtures/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ["./preserve-fn-case2.vue"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/trailing-slash-0.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
10 |
11 |
12 |
13 |
14 | Block with bg-red-500/50 class
15 |
16 |
17 | Block with bg-red-500 class
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/trailing-slash-0.js:
--------------------------------------------------------------------------------
1 | document.getElementById('#app').classList.add('bg-red-500 bg-red-500/50')
2 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/trailing-slash-1.js:
--------------------------------------------------------------------------------
1 | document.querySelector('#app').classList.add('bg-red-500/50 bg-red-500')
2 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/trailing-slash-2.js:
--------------------------------------------------------------------------------
1 | document.querySelector('#app').classList.add('bg-red-500 bg-red-500/50 bg-red-500 s bg-red-500')
2 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/trailing-slash.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
10 |
11 |
12 |
13 |
14 | Block with bg-red-500 class
15 |
16 |
17 | Block with bg-red-500/50 class
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packages/core/test/fixtures/vue-build-dist.js:
--------------------------------------------------------------------------------
1 | const mr = (e, t) => {
2 | const n = e.__vccOpts || e
3 | for (const [s, r] of t) n[s] = r
4 | return n
5 | }
6 | const fl = mr(cl, [['__scopeId', 'data-v-1d5be6d4']])
7 | const ul = bo(
8 | '

',
13 | 1
14 | )
15 | const al = Gs({
16 | __name: 'App',
17 | setup(e) {
18 | return (t, n) => (
19 | dr(),
20 | hr(
21 | fe,
22 | null,
23 | [
24 | ul,
25 | Ae(fl, {
26 | msg: 'Vite + Vue'
27 | })
28 | ],
29 | 64
30 | )
31 | )
32 | }
33 | })
34 | const dl = mr(al, [['__scopeId', 'data-v-fd6461cd']])
35 | Go(dl).mount('#app')
36 |
--------------------------------------------------------------------------------
/packages/core/test/html.test.ts:
--------------------------------------------------------------------------------
1 | import { Context } from '@/ctx'
2 | import { htmlHandler } from '@/html'
3 | import { splitCode } from '@tailwindcss-mangle/shared'
4 | import { getTestCase } from './utils'
5 |
6 | describe('html handler', () => {
7 | // let classGenerator: ClassGenerator
8 | let ctx: Context
9 | beforeEach(() => {
10 | // classGenerator = new ClassGenerator()
11 | ctx = new Context()
12 | })
13 | it('common usage', () => {
14 | const replaceMap = ctx.replaceMap
15 |
16 | for (const x of splitCode('text-3xl font-bold underline')) {
17 | replaceMap.set(x, '1')
18 | }
19 | const { code } = htmlHandler(getTestCase('hello-world.html'), {
20 | ctx,
21 | })
22 | expect(code).toMatchSnapshot()
23 | })
24 |
25 | it('trailing slash case', () => {
26 | const replaceMap = ctx.replaceMap
27 |
28 | for (const x of splitCode('bg-red-500 bg-red-500/50')) {
29 | replaceMap.set(x, '1')
30 | }
31 | const { code } = htmlHandler(getTestCase('trailing-slash.html'), {
32 | ctx,
33 | })
34 | expect(code).toMatchSnapshot()
35 | })
36 |
37 | it('trailing slash case 0', () => {
38 | const replaceMap = ctx.replaceMap
39 |
40 | for (const x of splitCode('bg-red-500 bg-red-500/50')) {
41 | replaceMap.set(x, '1')
42 | }
43 | const { code } = htmlHandler(getTestCase('trailing-slash-0.html'), {
44 | ctx,
45 | })
46 | expect(code).toMatchSnapshot()
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/packages/core/test/index.test.ts:
--------------------------------------------------------------------------------
1 | import { getCss, getTestCase } from './utils'
2 |
3 | describe('common usage', () => {
4 | it('hello-world', async () => {
5 | expect(await getCss(getTestCase('hello-world.html'))).toMatchSnapshot()
6 | })
7 |
8 | it('hello-world with js', async () => {
9 | expect(await getCss([getTestCase('hello-world.html'), getTestCase('hello-world.js')])).toMatchSnapshot()
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/packages/core/test/utils/index.ts:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs'
2 | import path from 'pathe'
3 | import postcss from 'postcss'
4 | import tailwindcss from 'tailwindcss'
5 |
6 | export function getTestCase(caseName: string) {
7 | return fs.readFileSync(path.resolve(__dirname, '../fixtures', caseName), 'utf8')
8 | }
9 | // @tailwind base;
10 | // @tailwind components;
11 | export async function getCss(raw: string | string[]) {
12 | if (typeof raw === 'string') {
13 | raw = [raw]
14 | }
15 | const res = await postcss([
16 | tailwindcss({
17 | content: raw.map((x) => {
18 | return {
19 | raw: x,
20 | }
21 | }),
22 | }),
23 | ]).process('@tailwind utilities;')
24 | return res.css
25 | }
26 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "@/*": [
7 | "src/*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "src",
13 | "test"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/core/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: [
5 | 'src/index.ts',
6 | ], // , 'src/cli.ts'],
7 | shims: true,
8 | format: ['cjs', 'esm'],
9 | clean: true,
10 | dts: true,
11 | // cjsInterop: true,
12 | // splitting: true,
13 | })
14 |
--------------------------------------------------------------------------------
/packages/core/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 | import { defineProject } from 'vitest/config'
3 |
4 | export default defineProject({
5 | test: {
6 | alias: [
7 | {
8 | find: '@',
9 | replacement: path.resolve(__dirname, './src'),
10 | },
11 | ],
12 | globals: true,
13 | testTimeout: 60_000,
14 | },
15 | })
16 |
--------------------------------------------------------------------------------
/packages/shared/README.md:
--------------------------------------------------------------------------------
1 | # @tailwindcss-mangle/shared
2 |
3 | The shared utils of tailwindcss-mangle
4 |
5 | ## Install
6 |
7 | ```bash
8 | i @tailwindcss-mangle/shared
9 | ```
10 |
11 | ## Usage
12 |
13 | ### ClassGenerator
14 |
15 | the class generator of tailwindcss-mangle
16 |
17 | ### escapeStringRegexp
18 |
19 | ### makeRegex
20 |
21 | ### splitCode
22 |
23 | ### defaultMangleClassFilter
24 |
--------------------------------------------------------------------------------
/packages/shared/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './classGenerator'
2 | export * from './regex'
3 | export * from './split'
4 | export * from './types'
5 | export * from './utils'
6 |
--------------------------------------------------------------------------------
/packages/shared/src/regex.ts:
--------------------------------------------------------------------------------
1 | export function escapeStringRegexp(str: string) {
2 | if (typeof str !== 'string') {
3 | throw new TypeError('Expected a string')
4 | }
5 | return str.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&').replaceAll('-', '\\x2d')
6 | }
7 |
8 | export interface MakeRegexOptions {
9 | /**
10 | * 这是为了进行精确提取用的
11 | * 比如同时出现了 bg-500 bg-500/50,
12 | * true 只会提取 bg-500
13 | * 而 false 会提取 2 个 bg-500
14 | */
15 | exact?: boolean
16 | }
17 |
18 | export function makeRegex(
19 | str: string,
20 | options: MakeRegexOptions = {
21 | exact: true,
22 | },
23 | ) {
24 | return new RegExp(`(?<=^|[\\s"])${escapeStringRegexp(str)}${options.exact ? '(?=$|[\\s"])' : ''}`, 'g')
25 | }
26 |
--------------------------------------------------------------------------------
/packages/shared/src/split.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line regexp/no-obscure-range
2 | export const validateFilterRE = /[\w\u00A0-\uFFFF%-?]/
3 |
4 | export function isValidSelector(selector = ''): selector is string {
5 | return validateFilterRE.test(selector)
6 | }
7 |
8 | export function splitCode(code: string, options: {
9 | splitQuote?: boolean
10 | } = { splitQuote: true }) {
11 | const regex = options.splitQuote ? /[\s"]+/ : /\s+/
12 | return code.split(regex).filter(x => isValidSelector(x))
13 | }
14 |
--------------------------------------------------------------------------------
/packages/shared/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface IClassGeneratorContextItem {
2 | name: string
3 | usedBy: Set
4 | }
5 |
6 | export interface IClassGeneratorOptions {
7 | reserveClassName?: (string | RegExp)[]
8 | customGenerate?: (original: string, opts: IClassGeneratorOptions, context: Record) => string | undefined
9 | log?: boolean
10 | exclude?: (string | RegExp)[]
11 | include?: (string | RegExp)[]
12 | ignoreClass?: (string | RegExp)[]
13 | classPrefix?: string
14 | }
15 |
16 | export interface IClassGenerator {
17 | newClassMap: Record
18 | newClassSize: number
19 | context: Record
20 | }
21 |
--------------------------------------------------------------------------------
/packages/shared/test/__snapshots__/reg.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`regex > trailing slash should exact match case 0 1`] = `
4 | [
5 | [
6 | "bg-red-500",
7 | ],
8 | [
9 | "bg-red-500",
10 | ],
11 | ]
12 | `;
13 |
14 | exports[`regex > trailing slash should exact match case 1 1`] = `
15 | [
16 | [
17 | "bg-red-500",
18 | ],
19 | ]
20 | `;
21 |
22 | exports[`regex > trailing slash should exact match case 2 1`] = `
23 | [
24 | [
25 | "bg-red-500",
26 | ],
27 | [
28 | "bg-red-500",
29 | ],
30 | ]
31 | `;
32 |
33 | exports[`regex > z-10 regex 1`] = `
34 | [
35 | [
36 | "z-10",
37 | ],
38 | ]
39 | `;
40 |
--------------------------------------------------------------------------------
/packages/shared/test/classGenerator.test.ts:
--------------------------------------------------------------------------------
1 | import { ClassGenerator } from '@/classGenerator'
2 |
3 | describe('classGenerator', () => {
4 | it('size 26*27+1', () => {
5 | const result: string[] = []
6 | const clsGen = new ClassGenerator()
7 | for (let i = 0; i < 26 * 27 + 1; i++) {
8 | result.push(clsGen.defaultClassGenerate())
9 | clsGen.newClassSize++
10 | }
11 | expect(result).toMatchSnapshot()
12 | })
13 |
14 | it('26*27+1', () => {
15 | const clsGen = new ClassGenerator()
16 | clsGen.newClassSize = 26 * 27
17 | expect(clsGen.defaultClassGenerate()).toBe('tw-aaa')
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/packages/shared/test/reg.test.ts:
--------------------------------------------------------------------------------
1 | import { makeRegex } from '@/regex'
2 |
3 | describe('regex', () => {
4 | it('z-10 regex', () => {
5 | const testCase = 'z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex'
6 | const regex = makeRegex('z-10')
7 | const arr = [...testCase.matchAll(regex)]
8 | expect(arr.length).toBe(1)
9 | expect(arr).toMatchSnapshot()
10 | })
11 |
12 | it('trailing slash should exact match case 0', () => {
13 | const testCase = 'bg-red-500 bg-red-500/50'
14 | const regex = makeRegex('bg-red-500', {
15 | exact: false,
16 | })
17 | const arr = [...testCase.matchAll(regex)]
18 | expect(arr.length).toBe(2)
19 | expect(arr).toMatchSnapshot()
20 | })
21 |
22 | it('trailing slash should exact match case 1', () => {
23 | const testCase = 'bg-red-500 bg-red-500/50'
24 | const regex = makeRegex('bg-red-500')
25 | const arr = [...testCase.matchAll(regex)]
26 | expect(arr.length).toBe(1)
27 | expect(arr).toMatchSnapshot()
28 | })
29 |
30 | it('trailing slash should exact match case 2', () => {
31 | const testCase = 's bg-red-500 bg-red-500/50 bg-red-500'
32 | const regex = makeRegex('bg-red-500')
33 | const arr = [...testCase.matchAll(regex)]
34 | expect(arr.length).toBe(2)
35 | expect(arr).toMatchSnapshot()
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/packages/shared/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "@/*": [
7 | "src/*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "src",
13 | "test"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/shared/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: [
5 | 'src/index.ts',
6 | ], // , 'src/cli.ts'],
7 | shims: true,
8 | format: ['cjs', 'esm'],
9 | clean: true,
10 | dts: true,
11 | // cjsInterop: true,
12 | // splitting: true,
13 | })
14 |
--------------------------------------------------------------------------------
/packages/shared/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 | import { defineProject } from 'vitest/config'
3 |
4 | export default defineProject({
5 | test: {
6 | alias: [
7 | {
8 | find: '@',
9 | replacement: path.resolve(__dirname, './src'),
10 | },
11 | ],
12 | globals: true,
13 | testTimeout: 60_000,
14 | },
15 | })
16 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/bin/tw-patch.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('../dist/cli.js')
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/dev/bin.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env -S npx tsx
2 | import '../src/cli.ts'
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/index.css:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss';
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/babel/index.ts:
--------------------------------------------------------------------------------
1 | import _babelGenerate from '@babel/generator'
2 | import _babelTraverse from '@babel/traverse'
3 |
4 | export { parse, parseExpression } from '@babel/parser'
5 |
6 | export function _interopDefaultCompat(e: any) {
7 | return e && typeof e === 'object' && 'default' in e ? e.default : e
8 | }
9 |
10 | export const generate = _interopDefaultCompat(_babelGenerate) as typeof _babelGenerate
11 |
12 | export const traverse = _interopDefaultCompat(_babelTraverse) as typeof _babelTraverse
13 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const pkgName = 'tailwindcss-patch'
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/core/index.ts:
--------------------------------------------------------------------------------
1 | export * from './cache'
2 | export * from './patcher'
3 | export * from './patches'
4 | export * from './runtime'
5 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/core/patches/index.ts:
--------------------------------------------------------------------------------
1 | export * from './exportContext'
2 | export * from './supportCustomUnits'
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/defaults.ts:
--------------------------------------------------------------------------------
1 | import type { InternalPatchOptions, PatchOptions } from './types'
2 | import process from 'node:process'
3 | import { defu } from '@tailwindcss-mangle/shared'
4 |
5 | export function getDefaultPatchOptions() {
6 | return {
7 | packageName: 'tailwindcss',
8 | applyPatches: {
9 | exportContext: true,
10 | extendLengthUnits: false,
11 | },
12 | overwrite: true,
13 | filter: () => true,
14 | }
15 | }
16 |
17 | export function getPatchOptions(options?: PatchOptions) {
18 | return defu[]>(
19 | options,
20 | {
21 | output: {
22 | removeUniversalSelector: true,
23 | },
24 | basedir: process.cwd(),
25 | },
26 | getDefaultPatchOptions(),
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './core'
2 | export { default as logger } from './logger'
3 | export * from './types'
4 | export { defineConfig } from '@tailwindcss-mangle/config'
5 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/logger.ts:
--------------------------------------------------------------------------------
1 | import { createConsola } from 'consola'
2 |
3 | const logger = createConsola()
4 |
5 | export default logger
6 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/src/utils.ts:
--------------------------------------------------------------------------------
1 | export function isObject(val: any) {
2 | return val !== null && typeof val === 'object' && Array.isArray(val) === false
3 | };
4 |
5 | export interface StringChange {
6 | start: number
7 | end: number
8 | replacement: string
9 | }
10 |
11 | /**
12 | * Apply the changes to the string such that a change in the length
13 | * of the string does not break the indexes of the subsequent changes.
14 | */
15 | export function spliceChangesIntoString(str: string, changes: StringChange[]) {
16 | // If there are no changes, return the original string
17 | if (!changes[0]) {
18 | return str
19 | }
20 |
21 | // Sort all changes in order to make it easier to apply them
22 | changes.sort((a, b) => {
23 | return a.end - b.end || a.start - b.start
24 | })
25 |
26 | // Append original string between each chunk, and then the chunk itself
27 | // This is sort of a String Builder pattern, thus creating less memory pressure
28 | let result = ''
29 |
30 | let previous = changes[0]
31 |
32 | result += str.slice(0, previous.start)
33 | result += previous.replacement
34 |
35 | for (let i = 1; i < changes.length; ++i) {
36 | const change = changes[i]
37 |
38 | result += str.slice(previous.end, change.start)
39 | result += change.replacement
40 |
41 | previous = change
42 | }
43 |
44 | // Add leftover string from last chunk to end
45 | result += str.slice(previous.end)
46 |
47 | return result
48 | }
49 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/__snapshots__/context.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`common usage > hello-world 1`] = `
4 | ".text-3xl {
5 | font-size: 1.875rem;
6 | line-height: 2.25rem
7 | }
8 | .font-bold {
9 | font-weight: 700
10 | }
11 | .underline {
12 | text-decoration-line: underline
13 | }"
14 | `;
15 |
16 | exports[`common usage > hello-world with js 1`] = `
17 | ".bg-\\[\\#123456\\] {
18 | --tw-bg-opacity: 1;
19 | background-color: rgb(18 52 86 / var(--tw-bg-opacity))
20 | }
21 | .text-3xl {
22 | font-size: 1.875rem;
23 | line-height: 2.25rem
24 | }
25 | .font-bold {
26 | font-weight: 700
27 | }
28 | .underline {
29 | text-decoration-line: underline
30 | }"
31 | `;
32 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/__snapshots__/defaults.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`defaults > getDefaultPatchOptions 1`] = `
4 | {
5 | "applyPatches": {
6 | "exportContext": true,
7 | "extendLengthUnits": false,
8 | },
9 | "filter": [Function],
10 | "overwrite": true,
11 | "packageName": "tailwindcss",
12 | }
13 | `;
14 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/__snapshots__/v4.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`v4 > extractRawCandidates case 0 1`] = `
4 | [
5 | "--x",
6 | "bg-[#123456]",
7 | "charset",
8 | "class",
9 | "content",
10 | "en",
11 | "initial-scale",
12 | "lang",
13 | "name",
14 | "text-(--x)",
15 | "text-xs",
16 | "viewport",
17 | "width",
18 | ]
19 | `;
20 |
21 | exports[`v4 > tailwindcssPatcher case 0 1`] = `
22 | [
23 | "bg-[#123456]",
24 | "content",
25 | "text-(--x)",
26 | "text-xs",
27 | ]
28 | `;
29 |
30 | exports[`v4 > tailwindcssPatcher case 1 1`] = `
31 | [
32 | "bg-[#123456]",
33 | "bg-gradient-to-b",
34 | "content",
35 | "from-[#2f73f1]",
36 | "h-[30px]",
37 | "text-(--x)",
38 | "text-xs",
39 | "to-[#4bcefd]",
40 | "w-[323px]",
41 | ]
42 | `;
43 |
44 | exports[`v4 > tailwindcssPatcher getClassSet case 2 1`] = `
45 | Set {
46 | "bg-[#123456]",
47 | "bg-gradient-to-b",
48 | "content",
49 | "from-[#2f73f1]",
50 | "h-[30px]",
51 | "text-(--x)",
52 | "text-xs",
53 | "to-[#4bcefd]",
54 | "w-[323px]",
55 | }
56 | `;
57 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/config.test.ts:
--------------------------------------------------------------------------------
1 | import { getConfig, getDefaultMangleUserConfig, getDefaultUserConfig, initConfig } from '@tailwindcss-mangle/config'
2 | import { deleteAsync } from 'del'
3 | import { existsSync } from 'fs-extra'
4 | import { resolve } from 'pathe'
5 | import { fixturesRoot } from './utils'
6 |
7 | describe('config', () => {
8 | it('0.default', async () => {
9 | const cwd = resolve(fixturesRoot, './config/0.default')
10 | const configPath = resolve(cwd, 'tailwindcss-mangle.config.ts')
11 | if (existsSync(configPath)) {
12 | await deleteAsync(configPath)
13 | }
14 |
15 | await initConfig(cwd)
16 | expect(existsSync(configPath)).toBe(true)
17 |
18 | const { config } = await getConfig(cwd)
19 | expect(config).toEqual(getDefaultUserConfig())
20 | })
21 |
22 | it('1.change-options', async () => {
23 | const cwd = resolve(fixturesRoot, './config/1.change-options')
24 | const { config } = await getConfig(cwd)
25 | expect(config).toEqual({
26 | patch: {
27 | output: {
28 | filename: 'xxx/yyy/zzz.json',
29 | loose: false,
30 | removeUniversalSelector: false,
31 | },
32 | tailwindcss: {
33 | cwd: 'aaa/bbb/cc',
34 | },
35 | },
36 | mangle: getDefaultMangleUserConfig(),
37 | })
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/defaults.test.ts:
--------------------------------------------------------------------------------
1 | import { getDefaultPatchOptions } from '@/defaults'
2 |
3 | describe('defaults', () => {
4 | it('getDefaultPatchOptions', () => {
5 | expect(getDefaultPatchOptions()).toMatchSnapshot()
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/.tw-patch/tw-class-list.json:
--------------------------------------------------------------------------------
1 | [
2 | "font-bold",
3 | "text-3xl",
4 | "underline"
5 | ]
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "0.common",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "tw-init": "npx tw-patch init",
8 | "tw-extract": "npx tw-patch extract"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC"
13 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/postcss.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | plugins: {
5 | tailwindcss: {
6 | config: path.resolve(__dirname, './tailwind.config.js')
7 | },
8 | autoprefixer: {},
9 | }
10 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Hello world!
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | /** @type {import('tailwindcss').Config} */
3 | module.exports = {
4 | content: [path.resolve(__dirname, "./src/**/*.{html,js}")],
5 | theme: {
6 | extend: {},
7 | },
8 | plugins: [],
9 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/0.common/tailwindcss-patch.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/.tw-patch/tw-class-list.json:
--------------------------------------------------------------------------------
1 | [
2 | "font-bold",
3 | "text-3xl",
4 | "underline"
5 | ]
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "1.default",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "tw-init": "npx tw-patch init",
8 | "tw-extract": "npx tw-patch extract"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC"
13 | }
14 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/postcss.config.js:
--------------------------------------------------------------------------------
1 | // const path = require('path')
2 |
3 | module.exports = {
4 | plugins: {
5 | tailwindcss: {}
6 | }
7 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Hello world!
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | /** @type {import('tailwindcss').Config} */
3 | module.exports = {
4 | content: ["./src/**/*.{html,js}"],//[path.resolve(__dirname, "./src/**/*.{html,js}")],
5 | theme: {
6 | extend: {},
7 | },
8 | plugins: [],
9 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/apps/1.default/tailwindcss-patch.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/cache/index.json:
--------------------------------------------------------------------------------
1 | ["*","bg-[#123456]","font-bold","text-3xl","underline"]
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/cache/merge-multiple-context.json:
--------------------------------------------------------------------------------
1 | ["*","text-[99px]","text-[100px]"]
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/cache/raw-method.json:
--------------------------------------------------------------------------------
1 | ["a","b","c"]
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/cli/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/config/0.default/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({})
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/config/1.change-options/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | patch: {
5 | output: {
6 | filename: 'xxx/yyy/zzz.json',
7 | loose: false,
8 | removeUniversalSelector: false,
9 | },
10 | tailwindcss: {
11 | cwd: 'aaa/bbb/cc',
12 | },
13 | },
14 | })
15 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/config/1.change-options/tailwindcss-patch.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | output: {
5 | filename: 'xxx/yyy/zzz.json',
6 | loose: false,
7 | removeUniversalSelector: false,
8 | },
9 | tailwindcss: {
10 | cwd: 'aaa/bbb/cc',
11 | },
12 | })
13 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/hello-world.css:
--------------------------------------------------------------------------------
1 | .text-3xl {
2 | font-size: 1.875rem;
3 | line-height: 2.25rem;
4 | }
5 | .font-bold {
6 | font-weight: 700;
7 | }
8 | .underline {
9 | text-decoration-line: underline;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/hello-world.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Hello world!
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/hello-world.js:
--------------------------------------------------------------------------------
1 | const el = document.getElementById('#app')
2 | el && el.classList.add('bg-[#123456]')
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/hello-world.wxml:
--------------------------------------------------------------------------------
1 | 111
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/img-url.jsx:
--------------------------------------------------------------------------------
1 | export function Hello() {
2 | return
3 | }
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/postcss7-compat/lib/jit/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.default = _default;
7 |
8 | var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext"));
9 |
10 | var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext"));
11 |
12 | var _sharedState = require("./lib/sharedState");
13 |
14 | var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
15 |
16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17 |
18 | function _default(configOrPath = {}) {
19 | return [_sharedState.env.DEBUG && function (root) {
20 | console.log('\n');
21 | console.time('JIT TOTAL');
22 | return root;
23 | }, function (root, result) {
24 | let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath);
25 | (0, _processTailwindFeatures.default)(setupContext)(root, result);
26 | }, _sharedState.env.DEBUG && function (root) {
27 | console.timeEnd('JIT TOTAL');
28 | console.log('\n');
29 | return root;
30 | }].filter(Boolean);
31 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/trailing-slash.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Block with bg-red-500 class
8 |
9 |
10 | Block with bg-red-500/50 class
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/v4/.gitignore:
--------------------------------------------------------------------------------
1 | !patch/dist
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/v4/deep/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/v4/index.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss" ;
2 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/v4/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/v4/patch/dist/a.mjs:
--------------------------------------------------------------------------------
1 | var K = ["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax","rpx"],
2 | Y = new RegExp(`^${g.source}(${K.join("|")})$`);
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/.eslintignore:
--------------------------------------------------------------------------------
1 | lts
2 | 3.*
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | es2021: true,
5 | node: true
6 | },
7 | extends: [
8 | 'standard'
9 | ],
10 | parserOptions: {
11 | ecmaVersion: 'latest',
12 | sourceType: 'module'
13 | },
14 | rules: {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/2/lib/jit/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.default = _default;
7 |
8 | var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext"));
9 |
10 | var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext"));
11 |
12 | var _sharedState = require("./lib/sharedState");
13 |
14 | var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
15 |
16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17 |
18 | function _default(configOrPath = {}) {
19 | return [_sharedState.env.DEBUG && function (root) {
20 | console.log('\n');
21 | console.time('JIT TOTAL');
22 | return root;
23 | }, function (root, result) {
24 | let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath);
25 | (0, _processTailwindFeatures.default)(setupContext)(root, result);
26 | }, _sharedState.env.DEBUG && function (root) {
27 | console.timeEnd('JIT TOTAL');
28 | console.log('\n');
29 | return root;
30 | }].filter(Boolean);
31 | }
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.2.6/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | if (process.env.OXIDE) {
3 | module.exports = require("./oxide/postcss-plugin");
4 | } else {
5 | module.exports = require("./plugin");
6 | }
7 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.2.7/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | if (process.env.OXIDE) {
3 | module.exports = require("./oxide/postcss-plugin");
4 | } else {
5 | module.exports = require("./plugin");
6 | }
7 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.0/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | if (process.env.OXIDE) {
3 | module.exports = require("./oxide/postcss-plugin");
4 | } else {
5 | module.exports = require("./plugin");
6 | }
7 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.1/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | if (process.env.OXIDE) {
3 | module.exports = require("./oxide/postcss-plugin");
4 | } else {
5 | module.exports = require("./plugin");
6 | }
7 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.2/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.3/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.4/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.5/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.6/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.3.7/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.0/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.1/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.12/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.14/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.2/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.3/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.4/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.5/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.6/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/3.4.7/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/README.md:
--------------------------------------------------------------------------------
1 | # tailwindcss-versions
2 |
3 | yarn add tailwindcss
4 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/install.js:
--------------------------------------------------------------------------------
1 | import { execa } from 'execa'
2 | // import { getCurrentFilename } from './utils.js'
3 | // import path from 'path'
4 | // import fs from 'fs/promises'
5 |
6 | const args = process.argv.slice(2)
7 |
8 | const version = args[0]
9 |
10 | if (version) {
11 | try {
12 | const cwd = process.cwd()
13 | // pnpm EPERM: operation not permitted,
14 | // try yarn
15 | const { stdout } = await execa('yarn', ['add', `tailwindcss${version}@npm:tailwindcss@${version}`], {
16 | cwd
17 | }).pipeStdout(process.stdout)
18 | // const filename = getCurrentFilename(import.meta.url)
19 | // const dirname = path.dirname(filename)
20 | // const nodeModulesPath = path.resolve(dirname, 'node_modules')
21 | // await fs.rmdir(path.resolve(nodeModulesPath, '.bin'))
22 | console.log(stdout)
23 | } catch (error) {
24 | console.error(error)
25 | }
26 | } else {
27 | console.warn('version is required!')
28 | }
29 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/lts/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = require("./plugin");
3 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/fixtures/versions/utils.js:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs/promises'
2 | import path from 'pathe'
3 | import { fileURLToPath } from 'node:url'
4 |
5 | export function getCurrentFilename (importMetaUrl) {
6 | return fileURLToPath(importMetaUrl)
7 | }
8 |
9 | export async function ensureDir (p) {
10 | await fs.mkdir(p, {
11 | recursive: true
12 | })
13 | }
14 |
15 | export async function copyFiles (arr) {
16 | if (Array.isArray(arr)) {
17 | for (let i = 0; i < arr.length; i++) {
18 | const { src, dest } = arr[i]
19 | await ensureDir(path.dirname(dest))
20 |
21 | const isExisted = await fs.access(src).then(() => true).catch(() => false)
22 |
23 | if (isExisted) {
24 | await fs.copyFile(src, dest)
25 | } else {
26 | console.warn(`[warning]: 404 ${src}`)
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/inspector.test.ts:
--------------------------------------------------------------------------------
1 | import { inspectPostcssPlugin, inspectProcessTailwindFeaturesReturnContext } from '@/core/patches/exportContext/postcss-v3'
2 | import fs from 'fs-extra'
3 | import path from 'pathe'
4 |
5 | const tailwindcssCasePath = path.resolve(__dirname, 'fixtures')
6 | const twltsLibPath = path.resolve(tailwindcssCasePath, 'versions/3.3.1/lib')
7 |
8 | describe('inspector', () => {
9 | it('inspectPostcssPlugin patch snap', () => {
10 | const rawCode = fs.readFileSync(path.resolve(twltsLibPath, 'plugin.js'), 'utf8')
11 | const { code, hasPatched } = inspectPostcssPlugin(rawCode)
12 | expect(hasPatched).toBe(false)
13 | expect(code).toMatchSnapshot()
14 | const { code: newCode, hasPatched: hasPatched0 } = inspectPostcssPlugin(code)
15 | expect(hasPatched0).toBe(true)
16 | expect(code).toBe(newCode)
17 | })
18 |
19 | it('inspectProcessTailwindFeaturesReturnContext patch snap', () => {
20 | const rawCode = fs.readFileSync(path.resolve(twltsLibPath, 'processTailwindFeatures.js'), 'utf8')
21 | const { code, hasPatched } = inspectProcessTailwindFeaturesReturnContext(rawCode)
22 | expect(hasPatched).toBe(false)
23 | expect(code).toMatchSnapshot()
24 | const { code: newCode, hasPatched: hasPatched0 } = inspectProcessTailwindFeaturesReturnContext(code)
25 | expect(hasPatched0).toBe(true)
26 | expect(code).toBe(newCode)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/patch.test.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { monkeyPatchForSupportingCustomUnitV4 } from '@/core/patches/supportCustomUnits/index'
3 | import { fixturesRoot } from './utils'
4 |
5 | describe('patch', () => {
6 | describe('monkeyPatchForSupportingCustomUnitV4', () => {
7 | it('should patch v4', () => {
8 | const { files } = monkeyPatchForSupportingCustomUnitV4(path.resolve(fixturesRoot, 'v4/patch'), {
9 |
10 | })
11 | expect(files.map((x) => {
12 | return {
13 | code: x.code,
14 | hasPatched: x.hasPatched,
15 | }
16 | })).toMatchSnapshot()
17 | })
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/pkg.test.ts:
--------------------------------------------------------------------------------
1 | import { isCI } from 'ci-info'
2 | import { getPackageInfoSync } from 'local-pkg'
3 | import { gte } from 'semver'
4 |
5 | describe.skipIf(isCI)('pkg', () => {
6 | it('tailwindcss', () => {
7 | const tailwindcss = getPackageInfoSync('tailwindcss')
8 | // @ts-ignore
9 | expect(gte(tailwindcss?.packageJson.version, '3.4.17')).toBe(true)
10 | })
11 |
12 | it('tailwindcss paths 0', () => {
13 | const tailwindcss = getPackageInfoSync('tailwindcss', {
14 | paths: [import.meta.dirname],
15 | })
16 | // @ts-ignore
17 | expect(gte(tailwindcss?.packageJson.version, '4.0.0')).toBe(true)
18 | })
19 |
20 | it('tailwindcss paths 1', () => {
21 | const tailwindcss = getPackageInfoSync('tailwindcss', {
22 | paths: [process.cwd()],
23 | })
24 | expect(tailwindcss?.packageJson.version).toBe('3.4.17')
25 | })
26 |
27 | it('tailwindcss3', () => {
28 | const tailwindcss = getPackageInfoSync('tailwindcss-3')
29 | expect(tailwindcss?.packageJson.version).toBe('3.4.17')
30 | })
31 |
32 | // it('tailwindcss4', () => {
33 | // const tailwindcss = getPackageInfoSync('tailwindcss-4')
34 | // expect(tailwindcss?.packageJson.version).toBe('4.0.6')
35 | // })
36 | })
37 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/postcss7-v2.test.ts:
--------------------------------------------------------------------------------
1 | import { inspectPostcssPlugin, inspectProcessTailwindFeaturesReturnContext } from '@/core/patches/exportContext/postcss-v2'
2 | import { getTestCase } from './utils'
3 |
4 | describe('postcss7-compat', () => {
5 | it('processTailwindFeatures patch', async () => {
6 | const code = getTestCase('postcss7-compat/lib/jit/processTailwindFeatures.js')
7 | const r = inspectProcessTailwindFeaturesReturnContext(code)
8 |
9 | expect(r.code).toMatchSnapshot()
10 | expect(r.hasPatched).toBe(false)
11 | })
12 |
13 | it('jit plugins patch', async () => {
14 | const code = getTestCase('postcss7-compat/lib/jit/index.js')
15 | const r = inspectPostcssPlugin(code)
16 |
17 | expect(r.code).toMatchSnapshot()
18 | expect(r.hasPatched).toBe(false)
19 | })
20 |
21 | it('jit plugins patch case 0', async () => {
22 | const code = getTestCase('postcss7-compat/lib/jit/index.js')
23 | let r = inspectPostcssPlugin(code)
24 | expect(r.hasPatched).toBe(false)
25 | r = inspectPostcssPlugin(r.code)
26 | expect(r.code).toMatchSnapshot()
27 | expect(r.hasPatched).toBe(true)
28 | })
29 | })
30 |
31 | // const XXXEnum = {
32 | // A: 1,
33 | // B: 2,
34 | // C: 'xxx'
35 | // } as const
36 |
37 | // type EnumType = (T)[keyof T]
38 |
39 | // function xx(x: EnumType) {
40 |
41 | // }
42 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/splice-changes-into-string.ts:
--------------------------------------------------------------------------------
1 | export interface StringChange {
2 | start: number
3 | end: number
4 | replacement: string
5 | }
6 |
7 | /**
8 | * Apply the changes to the string such that a change in the length
9 | * of the string does not break the indexes of the subsequent changes.
10 | */
11 | export function spliceChangesIntoString(str: string, changes: StringChange[]) {
12 | // If there are no changes, return the original string
13 | if (!changes[0]) {
14 | return str
15 | }
16 |
17 | // Sort all changes in order to make it easier to apply them
18 | changes.sort((a, b) => {
19 | return a.end - b.end || a.start - b.start
20 | })
21 |
22 | // Append original string between each chunk, and then the chunk itself
23 | // This is sort of a String Builder pattern, thus creating less memory pressure
24 | let result = ''
25 |
26 | let previous = changes[0]
27 |
28 | result += str.slice(0, previous.start)
29 | result += previous.replacement
30 |
31 | for (let i = 1; i < changes.length; ++i) {
32 | const change = changes[i]
33 |
34 | result += str.slice(previous.end, change.start)
35 | result += change.replacement
36 |
37 | previous = change
38 | }
39 |
40 | // Add leftover string from last chunk to end
41 | result += str.slice(previous.end)
42 |
43 | return result
44 | }
45 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/src/candidate.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/tailwindcss-patch/test/src/candidate.ts
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/src/utils/design-system.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/tailwindcss-patch/test/src/utils/design-system.ts
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { existsSync, statSync } from 'node:fs'
2 | import { deleteAsync } from 'del'
3 | import fs from 'fs-extra'
4 | import path from 'pathe'
5 | import { fixturesRoot } from './utils'
6 |
7 | describe('utils', () => {
8 | it('ensureDir', async () => {
9 | const dir = path.resolve(fixturesRoot, './xxx/yyy')
10 | if (existsSync(dir)) {
11 | await deleteAsync(dir)
12 | }
13 | expect(existsSync(dir)).toBe(false)
14 | await fs.ensureDir(dir)
15 | const stat = statSync(dir)
16 | expect(stat.isDirectory()).toBe(true)
17 | expect(existsSync(dir)).toBe(true)
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/test/utils.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs-extra'
2 | import path from 'pathe'
3 | import postcss from 'postcss'
4 | import tailwindcss from 'tailwindcss-3'
5 |
6 | export const fixturesRoot = path.resolve(__dirname, './fixtures')
7 |
8 | export const appRoot = path.resolve(fixturesRoot, './apps')
9 |
10 | export function getTestCase(caseName: string) {
11 | return fs.readFileSync(path.resolve(__dirname, 'fixtures', caseName), 'utf8')
12 | }
13 | // @tailwind base;
14 | // @tailwind components;
15 | export async function getCss(raw: string | string[]) {
16 | if (typeof raw === 'string') {
17 | raw = [raw]
18 | }
19 | const res = await postcss([
20 | tailwindcss({
21 | content: raw.map((x) => {
22 | return {
23 | raw: x,
24 | }
25 | }),
26 | }),
27 | ]).process('@tailwind utilities;', {
28 | from: undefined,
29 | })
30 | return res.css
31 | }
32 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "@/*": [
7 | "src/*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "src",
13 | "test",
14 | "dev"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: ['src/index.ts', 'src/cli.ts'],
5 | shims: true,
6 | clean: true,
7 | format: ['cjs', 'esm'], // , 'esm'
8 | dts: true,
9 | cjsInterop: true,
10 | splitting: true,
11 | external: ['tailwindcss', '@tailwindcss/node', '@tailwindcss/oxide'],
12 | })
13 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 | import { defineProject } from 'vitest/config'
3 |
4 | export default defineProject({
5 | test: {
6 | alias: [
7 | {
8 | find: '@',
9 | replacement: path.resolve(__dirname, './src'),
10 | },
11 | ],
12 | globals: true,
13 | testTimeout: 60_000,
14 | setupFiles: ['./vitest.setup.ts'],
15 | coverage: {
16 | enabled: true,
17 | all: false,
18 | },
19 | },
20 | })
21 |
--------------------------------------------------------------------------------
/packages/tailwindcss-patch/vitest.setup.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/tailwindcss-patch/vitest.setup.ts
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const pluginName = 'unplugin-tailwindcss-mangle'
2 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/core/index.ts:
--------------------------------------------------------------------------------
1 | import factory from './factory'
2 | import unplugin from './plugin'
3 |
4 | export {
5 | factory,
6 | unplugin,
7 | }
8 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/core/plugin.ts:
--------------------------------------------------------------------------------
1 | import { createUnplugin } from 'unplugin'
2 | import factory from './factory'
3 |
4 | const unplugin = createUnplugin(factory)
5 |
6 | export default unplugin
7 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/esbuild.ts:
--------------------------------------------------------------------------------
1 | import { unplugin } from './core'
2 |
3 | export default unplugin.esbuild
4 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/globals.d.ts:
--------------------------------------------------------------------------------
1 | declare const __DEV__: boolean
2 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/index.ts:
--------------------------------------------------------------------------------
1 | export { unplugin as default } from './core'
2 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/loader.ts:
--------------------------------------------------------------------------------
1 | import type { Context } from '@tailwindcss-mangle/core'
2 | import type { LoaderContext } from 'webpack'
3 | import { cssHandler } from '@tailwindcss-mangle/core'
4 |
5 | const TailwindcssMangleWebpackLoader = async function (this: LoaderContext<{ ctx: Context }>, source: string) {
6 | const callback = this.async()
7 | const { ctx } = this.getOptions()
8 |
9 | const { code } = await cssHandler(source, {
10 | ctx,
11 | id: this.resource,
12 | })
13 |
14 | callback(null, code)
15 | }
16 |
17 | export default TailwindcssMangleWebpackLoader
18 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/nuxt.ts:
--------------------------------------------------------------------------------
1 | import type { MangleUserConfig } from './types'
2 | import { unplugin } from './core'
3 |
4 | export default function (options: MangleUserConfig = {}, nuxt: any) {
5 | // install webpack plugin
6 | nuxt.hook('webpack:config', (config: any) => {
7 | config.plugins = config.plugins || []
8 | config.plugins.unshift(unplugin.webpack(options))
9 | })
10 |
11 | // install vite plugin
12 | nuxt.hook('vite:extendConfig', (config: any) => {
13 | config.plugins = config.plugins || []
14 | config.plugins.push(unplugin.vite(options))
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/rollup.ts:
--------------------------------------------------------------------------------
1 | import { unplugin } from './core'
2 |
3 | export default unplugin.rollup
4 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/types.ts:
--------------------------------------------------------------------------------
1 | export type * from '@tailwindcss-mangle/config'
2 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/vite.ts:
--------------------------------------------------------------------------------
1 | import type {} from 'vite'
2 | import { unplugin } from './core'
3 |
4 | export default unplugin.vite
5 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/src/webpack.ts:
--------------------------------------------------------------------------------
1 | import { unplugin } from './core'
2 |
3 | export default unplugin.webpack
4 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/context.test.ts:
--------------------------------------------------------------------------------
1 | function createContext() {
2 | let a = 1
3 | function inc() {
4 | a++
5 | }
6 | return {
7 | a,
8 | inc,
9 | }
10 | }
11 |
12 | describe('contxt', () => {
13 | it('contxt change', () => {
14 | const ctx = createContext()
15 | expect(ctx.a).toBe(1)
16 | ctx.inc()
17 | expect(ctx.a).toBe(1)
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/fallback/tailwindcss-mangle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tailwindcss-patch'
2 |
3 | export default defineConfig({
4 | mangle: {
5 | classListPath: './index.json',
6 | },
7 | })
8 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/tsx/app.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
7 |
8 |
9 |
10 | )
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/.gitkeep
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-typescript-starter",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview",
10 | "extract": "npx tw-patch extract"
11 | },
12 | "devDependencies": {
13 | "typescript": "^5.0.2",
14 | "vite": "^4.3.9"
15 | }
16 | }
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | plugins: {
5 | tailwindcss: {
6 | config: path.resolve(__dirname, './tailwind.config.cjs')
7 | },
8 | // autoprefixer: {},
9 | }
10 | }
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/src/counter.ts:
--------------------------------------------------------------------------------
1 | export function setupCounter(element: HTMLButtonElement) {
2 | element.animate({
3 | clipPath: [],
4 | }, {
5 | duration: 400,
6 | easing: 'ease-out',
7 | })
8 | }
9 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/src/style.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | module.exports = {
5 | content: [path.resolve(__dirname, "./src/**/*.{html,js,ts}")],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | corePlugins: {
11 | preflight: false
12 | }
13 | }
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/vite-repo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true
21 | },
22 | "include": ["src"]
23 | }
24 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/.gitkeep
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-repo",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC"
12 | }
13 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/postcss.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | plugins: {
5 | tailwindcss: {
6 | config: path.resolve(__dirname, './tailwind.config.js')
7 | },
8 | // autoprefixer: {},
9 | }
10 | }
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 | bg-[#123456]
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/test/fixtures/webpack-repo/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | module.exports = {
5 | content: [path.resolve(__dirname, "./src/**/*.{html,js,ts}")],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | corePlugins: {
11 | preflight: false
12 | }
13 | }
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "@/*": [
7 | "src/*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "src",
13 | "test"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: [
5 | 'src/index.ts',
6 | 'src/vite.ts',
7 | 'src/esbuild.ts',
8 | 'src/nuxt.ts',
9 | 'src/rollup.ts',
10 | 'src/webpack.ts',
11 | 'src/utils.ts',
12 | 'src/loader.ts',
13 | ], // , 'src/cli.ts'],
14 | shims: true,
15 | format: ['cjs', 'esm'],
16 | clean: true,
17 | dts: true,
18 | cjsInterop: true,
19 | splitting: true,
20 | define: {
21 | __DEV__: 'false',
22 | },
23 | })
24 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'pathe'
2 | import { defineProject } from 'vitest/config'
3 |
4 | export default defineProject({
5 | define: {
6 | __DEV__: true,
7 | },
8 | test: {
9 | alias: [
10 | {
11 | find: '@',
12 | replacement: path.resolve(__dirname, './src'),
13 | },
14 | ],
15 | globals: true,
16 | testTimeout: 60_000,
17 | setupFiles: ['./vitest.setup.ts'],
18 | },
19 |
20 | // build: {
21 | // commonjsOptions: {
22 | // transformMixedEsModules: true
23 | // }
24 | // }
25 | })
26 |
--------------------------------------------------------------------------------
/packages/unplugin-tailwindcss-mangle/vitest.setup.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonofmagic/tailwindcss-mangle/b21d639f21c84418fd04cdf2961ed77ea07fa141/packages/unplugin-tailwindcss-mangle/vitest.setup.ts
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - packages/*
3 | - scripts/*
4 | - website
5 | onlyBuiltDependencies:
6 | - esbuild
7 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended"
5 | ],
6 | // https://answers.netlify.com/t/how-to-prevent-deploy-previews-for-renovate-prs/44131/3
7 | "commitBody": "[skip netlify]"
8 | }
9 |
--------------------------------------------------------------------------------
/scripts/postcss7-compat/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('node:fs')
2 | const path = require('pathe')
3 | const postcss = require('postcss')
4 | const tailwindcss = require('tailwindcss')
5 | const { TailwindcssPatcher } = require('tailwindcss-patch')
6 |
7 | async function main() {
8 | const twPatcher = new TailwindcssPatcher()
9 | twPatcher.patch()
10 |
11 | const tw = tailwindcss({
12 | mode: 'jit',
13 | purge: {
14 | content: [{
15 | raw: 'w-[99px]',
16 | }],
17 | },
18 | // corePlugins: {
19 | // preflight: false
20 | // }
21 | })
22 | const result = postcss([tw]).process(`@tailwind base;
23 | @tailwind components;
24 | @tailwind utilities;`)
25 | // console.log(result.css)
26 | fs.writeFileSync(path.join(__dirname, 'result.css'), result.css, 'utf8')
27 |
28 | // const ctx = require('tailwindcss/lib/jit/index')
29 | // console.log(ctx)
30 |
31 | const ctx = twPatcher.getClassSet()
32 | console.log(ctx)
33 | }
34 |
35 | main()
36 |
--------------------------------------------------------------------------------
/scripts/postcss7-compat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss7-compat",
3 | "version": "0.0.18",
4 | "private": true,
5 | "description": "",
6 | "author": "",
7 | "license": "ISC",
8 | "keywords": [],
9 | "main": "index.js",
10 | "scripts": {
11 | "start": "node .",
12 | "do-patch": "tw-patch install"
13 | },
14 | "dependencies": {
15 | "tailwindcss-patch": "workspace:^"
16 | },
17 | "devDependencies": {
18 | "autoprefixer": "^10.4.21",
19 | "postcss": "^8.5.3",
20 | "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/stylelint.config.js:
--------------------------------------------------------------------------------
1 | import { icebreaker } from '@icebreakers/stylelint-config'
2 |
3 | export default icebreaker()
4 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "moduleResolution": "Bundler",
6 | "resolveJsonModule": true,
7 | "types": [
8 | "vitest/globals"
9 | ],
10 | "allowJs": true,
11 | "strict": true,
12 | "allowSyntheticDefaultImports": true,
13 | "esModuleInterop": true,
14 | "skipLibCheck": true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "tasks": {
4 | "build": {
5 | "dependsOn": [
6 | "^build"
7 | ],
8 | "outputs": [
9 | "dist/**"
10 | ]
11 | },
12 | "lint": {
13 | "outputs": []
14 | },
15 | "dev": {
16 | "cache": false
17 | },
18 | "test": {
19 | "dependsOn": [
20 | "^build"
21 | ]
22 | },
23 | "release": {},
24 | "sync": {}
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------
1 | import { defineWorkspace } from 'vitest/config'
2 |
3 | export default defineWorkspace(
4 | [
5 | 'packages/*',
6 | ],
7 | )
8 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | public/_pagefind
2 | .env
--------------------------------------------------------------------------------
/website/.tw-patch/tw-class-list.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/website/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @tailwindcss-mangle/website
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [`0404f90`](https://github.com/sonofmagic/tailwindcss-mangle/commit/0404f90cc10716a84f3137f4c76a58c4c7edf019) Thanks [@sonofmagic](https://github.com/sonofmagic)! - feat: support tailwindcss@4.1.1
8 |
9 | ## 1.0.1
10 |
11 | ### Patch Changes
12 |
13 | - [`034f9f3`](https://github.com/sonofmagic/tailwindcss-mangle/commit/034f9f30ebfee915a564f95e2bf1959e8fbce3e6) Thanks [@sonofmagic](https://github.com/sonofmagic)! - chore: bump deps and add patch only for tailwindcss v2 and v3
14 |
--------------------------------------------------------------------------------
/website/app/[lang]/[[...mdxPath]]/page.tsx:
--------------------------------------------------------------------------------
1 | import { generateStaticParamsFor, importPage } from 'nextra/pages'
2 | import { useMDXComponents } from '../../../mdx-components'
3 |
4 | export const generateStaticParams = generateStaticParamsFor('mdxPath')
5 |
6 | export async function generateMetadata(props: PageProps) {
7 | const params = await props.params
8 | const { metadata } = await importPage(params.mdxPath, params.lang)
9 | return metadata
10 | }
11 |
12 | type PageProps = Readonly<{
13 | params: Promise<{
14 | mdxPath: string[]
15 | lang: string
16 | }>
17 | }>
18 | const Wrapper = useMDXComponents().wrapper
19 |
20 | export default async function Page(props: PageProps) {
21 | const params = await props.params
22 | const result = await importPage(params.mdxPath, params.lang)
23 | const { default: MDXContent, toc, metadata } = result
24 | return (
25 |
26 |
27 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/website/app/[lang]/not-found.ts:
--------------------------------------------------------------------------------
1 | export { NotFoundPage as default } from 'nextra-theme-docs'
2 |
--------------------------------------------------------------------------------
/website/app/[lang]/styles.css:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss';
2 | @import 'nextra-theme-docs/style.css';
3 | @import '../_components/features.css';
4 |
5 | @theme {
6 | }
7 |
8 | body {
9 | --bg-dot-color: #d1d1d1;
10 |
11 | .dark & {
12 | --bg-dot-color: #313131;
13 | }
14 |
15 | background:
16 | linear-gradient(to bottom, transparent, rgb(var(--nextra-bg)) 300px),
17 | fixed 0 0 / 20px 20px
18 | radial-gradient(var(--bg-dot-color) 1px, transparent 0),
19 | fixed 10px 10px / 20px 20px
20 | radial-gradient(var(--bg-dot-color) 1px, transparent 0);
21 | }
22 |
--------------------------------------------------------------------------------
/website/app/_components/authors.tsx:
--------------------------------------------------------------------------------
1 | import type { Locale } from '@app/_dictionaries/i18n-config'
2 | import type { FC } from 'react'
3 | import { getDictionary } from '@app/_dictionaries/get-dictionary'
4 |
5 | export const TopContent: FC<{
6 | title: string
7 | date: string
8 | authors: {
9 | name: string
10 | link: string
11 | }[]
12 | lang: Locale
13 | }> = async ({ title, date, authors, lang }) => {
14 | const dictionary = await getDictionary(lang)
15 | const dateObj = new Date(date)
16 | return (
17 | <>
18 | {title}
19 |
20 |
27 | {' '}
28 | {dictionary.by}
29 | {' '}
30 | {authors.map(author => (
31 |
32 |
38 | {author.name}
39 |
40 |
41 | ))}
42 |
43 | >
44 | )
45 | }
46 |
--------------------------------------------------------------------------------
/website/app/_components/features.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: grid;
3 | grid-template-columns: 1fr 1fr 1fr 1fr;
4 | gap: 1rem 2rem;
5 | margin: 2.5rem 0 2rem;
6 | }
7 | .feature {
8 | @apply inline-flex items-center gap-2 max-sm:justify-center;
9 | }
10 | .feature h4 {
11 | font-weight: 700;
12 | font-size: 1.1rem;
13 | white-space: nowrap;
14 | }
15 | @media (max-width: 860px) {
16 | .features {
17 | gap: 1rem 0.5rem;
18 | }
19 | .feature h4 {
20 | font-size: 0.9rem;
21 | }
22 | }
23 | @media (max-width: 660px) {
24 | .features {
25 | grid-template-columns: 1fr 1fr;
26 | }
27 | }
28 | @media (max-width: 370px) {
29 | .feature h4 {
30 | font-size: 0.8rem;
31 | }
32 | .feature svg {
33 | width: 16px;
34 | stroke-width: 2.5px;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/website/app/_dictionaries/en.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | dark: 'Dark',
3 | light: 'Light',
4 | system: 'System',
5 | backToTop: 'Scroll to top',
6 | lastUpdated: 'Last updated on',
7 | logo: {
8 | title: 'React Hooks for Data Fetching',
9 | },
10 | poweredBy: 'Powered by',
11 | lightweight: 'Lightweight',
12 | realtime: 'Realtime',
13 | suspense: 'Suspense',
14 | pagination: 'Pagination',
15 | backendAgnostic: 'Backend Agnostic',
16 | renderingStrategies: 'SSR / SSG Ready',
17 | typescript: 'TypeScript Ready',
18 | remoteLocal: 'Remote + Local',
19 | editPage: 'Edit this page on GitHub',
20 | by: 'by',
21 | }
22 |
--------------------------------------------------------------------------------
/website/app/_dictionaries/get-dictionary.ts:
--------------------------------------------------------------------------------
1 | import type { Dictionaries, Dictionary, Locale } from './i18n-config'
2 | import 'server-only'
3 |
4 | // We enumerate all dictionaries here for better linting and TypeScript support
5 | // We also get the default import for cleaner types
6 | const dictionaries: Dictionaries = {
7 | en: () => import('./en'),
8 | zh: () => import('./zh'),
9 | }
10 |
11 | export async function getDictionary(locale: string): Promise {
12 | const { default: dictionary } = await (
13 | dictionaries[locale] || dictionaries.en
14 | )()
15 |
16 | return dictionary
17 | }
18 |
19 | export function getDirection(locale: Locale): 'ltr' | 'rtl' {
20 | return 'ltr'
21 | }
22 |
--------------------------------------------------------------------------------
/website/app/_dictionaries/i18n-config.ts:
--------------------------------------------------------------------------------
1 | import type EnglishLocale from './en'
2 |
3 | export const i18n = {
4 | defaultLocale: 'en',
5 | locales: ['en', 'zh'],
6 | } as const
7 |
8 | export type Locale = (typeof i18n)['locales'][number]
9 |
10 | export type Dictionary = typeof EnglishLocale
11 |
12 | export type Dictionaries = Record<
13 | Locale,
14 | () => Promise<{ default: Dictionary }>
15 | >
16 |
--------------------------------------------------------------------------------
/website/app/_dictionaries/zh.ts:
--------------------------------------------------------------------------------
1 | import type { Dictionary } from './i18n-config'
2 |
3 | export default {
4 | dark: 'Dark',
5 | light: 'Light',
6 | system: 'System',
7 | backToTop: 'Scroll to top',
8 | lastUpdated: 'Last updated on',
9 | logo: {
10 | title: 'React Hooks for Data Fetching',
11 | },
12 | poweredBy: 'Powered by',
13 | lightweight: 'Lightweight',
14 | realtime: 'Realtime',
15 | suspense: 'Suspense',
16 | pagination: 'Pagination',
17 | backendAgnostic: 'Backend Agnostic',
18 | renderingStrategies: 'SSR / SSG Ready',
19 | typescript: 'TypeScript Ready',
20 | remoteLocal: 'Remote + Local',
21 | editPage: 'Edit this page on GitHub',
22 | by: 'by',
23 | } satisfies Dictionary
24 |
--------------------------------------------------------------------------------
/website/app/env.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.mdx' {
2 | import type { MDXComponents } from 'nextra/mdx-components'
3 | import type { FC } from 'react'
4 |
5 | const ReactComponent: FC<{
6 | components?: MDXComponents
7 | }>
8 | export default ReactComponent
9 | }
10 |
11 | declare module '*.svg?svgr' {
12 | import type { FC, SVGProps } from 'react'
13 |
14 | const ReactComponent: FC>
15 |
16 | export default ReactComponent
17 | }
18 |
--------------------------------------------------------------------------------
/website/content/en/_meta.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'index': 'Homepage',
3 | '---': {
4 | type: 'separator',
5 | },
6 | 'patch': '1.Patch',
7 | 'mangle': '2.Mangle',
8 | 'config': '3.Config',
9 | 'recommend': {
10 | display: 'hidden',
11 | },
12 | }
13 |
--------------------------------------------------------------------------------
/website/content/en/config.mdx:
--------------------------------------------------------------------------------
1 | # 待办事项
--------------------------------------------------------------------------------
/website/content/en/index.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra/components'
2 |
3 | # Welcome to Tailwindcss-mangle
4 |
5 | ## What is tailwindcss-mangle?
6 |
7 | This is a project designed to compress and obfuscate class names generated by `tailwindcss`.
8 |
9 | The purpose of creating this library is that the pages we develop using `tailwindcss` are too easily copied and plagiarized.
10 |
11 | Using `tailwindcss-mangle` can add a little cost to those who attempt to copy.
12 |
13 | ## How to use?
14 |
15 | Currently, the usage is mainly divided into `2` steps:
16 |
17 | 1. `Patch`
18 | 2. `Mangle`
19 |
20 | ## Patch
21 |
22 | This step is used to patch `tailwindcss` to expose its context, thereby extracting the `Token` it generates from its internals.
23 |
24 | Finally, it exports this into a `Json` file.
25 |
26 | ## Mangle
27 |
28 | Read the `Json` exported by `Patch`, and escape all string literals and template strings corresponding to the `Token` inside.
--------------------------------------------------------------------------------
/website/content/zh/_meta.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'index': 'Homepage',
3 | '---': {
4 | type: 'separator',
5 | },
6 | 'patch': '1.Patch',
7 | 'mangle': '2.Mangle',
8 | 'config': '3.Config',
9 | 'recommend': {
10 | display: 'hidden',
11 | },
12 | }
13 |
--------------------------------------------------------------------------------
/website/content/zh/config.mdx:
--------------------------------------------------------------------------------
1 | # TODO
--------------------------------------------------------------------------------
/website/content/zh/index.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra/components'
2 |
3 | # 欢迎来到 Tailwindcss-mangle
4 |
5 | ## 什么是 tailwindcss-mangle ?
6 |
7 | 这是一个给 `tailwindcss` 生成的类名进行压缩混淆的一个项目。
8 |
9 | 制作这个库的目的在于,我们使用 `tailwindcss` 开发的页面,实在是太容易被拷贝抄袭了。
10 |
11 | 而使用 `tailwindcss-mangle` 就能来给抄袭者带去一点点的抄袭成本。
12 |
13 | ## 如何使用?
14 |
15 | 目前使用方式上,主要分为 `2` 步:
16 |
17 | 1. `Patch`
18 | 2. `Mangle`
19 |
20 | ## Patch
21 |
22 | 此步骤用于给 `tailwindcss` 打上暴露上下文的补丁,从而从它的内部提取出它提取的 `Token`
23 |
24 | 最终把它导出成一个 `Json` 文件。
25 |
26 | ## Mangle
27 |
28 | 读取 `Patch` 导出的 `Json` , 将里面的 `Token` 对应的字符串字面量和模板字符串全部转义。
29 |
30 |
31 |
--------------------------------------------------------------------------------
/website/mdx-components.ts:
--------------------------------------------------------------------------------
1 | import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'
2 | import { Pre, withIcons } from 'nextra/components'
3 | import { GitHubIcon } from 'nextra/icons'
4 |
5 | const docsComponents = getDocsMDXComponents({
6 | pre: withIcons(Pre, { js: GitHubIcon })
7 | })
8 |
9 | export const useMDXComponents: typeof getDocsMDXComponents = components => ({
10 | ...docsComponents,
11 | ...components
12 | })
13 |
--------------------------------------------------------------------------------
/website/middleware.ts:
--------------------------------------------------------------------------------
1 | export { middleware } from 'nextra/locales'
2 |
3 | export const config = {
4 | // Matcher ignoring `/_next/` and `/api/`
5 | matcher: [
6 | '/((?!api|_next/static|_next/image|favicon.ico|icon.svg|apple-icon.png|manifest|_pagefind).*)'
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/website/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
6 |
--------------------------------------------------------------------------------
/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@tailwindcss-mangle/website",
3 | "type": "module",
4 | "version": "1.1.0",
5 | "private": true,
6 | "description": "",
7 | "author": "",
8 | "license": "ISC",
9 | "keywords": [],
10 | "scripts": {
11 | "analyze": "ANALYZE=true pnpm build",
12 | "build": "next build",
13 | "debug": "NODE_OPTIONS='--inspect' next dev",
14 | "dev": "next --turbopack",
15 | "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind",
16 | "start": "next start",
17 | "types:check": "tsc --noEmit",
18 | "translate": "tsx scripts/translate.ts"
19 | },
20 | "dependencies": {
21 | "markdown-to-jsx": "^7.7.6",
22 | "next": "^15.3.1",
23 | "nextra": "^4.2.17",
24 | "nextra-theme-docs": "^4.2.17",
25 | "react": "19.1.0",
26 | "react-dom": "19.1.0",
27 | "react-intersection-observer": "^9.16.0"
28 | },
29 | "devDependencies": {
30 | "@next/bundle-analyzer": "^15.3.1",
31 | "@svgr/webpack": "^8.1.0",
32 | "@tailwindcss/postcss": "^4.1.7",
33 | "@types/react": "19.1.5",
34 | "pagefind": "^1.3.0",
35 | "tailwindcss": "^4.0.9"
36 | },
37 | "browserslist": [
38 | ">= .25%",
39 | "not dead"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/website/postcss.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss').Postcss} */
2 | export default {
3 | plugins: {
4 | '@tailwindcss/postcss': {}
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/website/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: [
4 | './pages/**/*.{js,jsx,ts,tsx,md,mdx}',
5 | './components/**/*.{js,jsx,ts,tsx,md,mdx}',
6 | './theme.config.tsx',
7 | ],
8 | theme: {
9 | extend: {},
10 | },
11 | plugins: [],
12 | }
13 |
--------------------------------------------------------------------------------
/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": false,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "incremental": true,
11 | "esModuleInterop": true,
12 | "module": "esnext",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "moduleResolution": "bundler",
17 | "baseUrl": "./",
18 | "paths": {
19 | "@app/*": ["./app/*"]
20 | },
21 | "plugins": [
22 | {
23 | "name": "next"
24 | }
25 | ],
26 | "strictNullChecks": true,
27 | "noUncheckedIndexedAccess": true
28 | },
29 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
30 | "exclude": ["node_modules", ".next"]
31 | }
32 |
--------------------------------------------------------------------------------