├── example ├── umijs │ ├── mock │ │ └── .gitkeep │ ├── src │ │ ├── global.css │ │ ├── app.ts │ │ └── pages │ │ │ ├── index.css │ │ │ └── index.tsx │ ├── .prettierignore │ ├── README.md │ ├── .prettierrc │ ├── typings.d.ts │ ├── .editorconfig │ ├── .gitignore │ ├── .umirc.ts │ ├── windi.config.ts │ ├── tsconfig.json │ └── package.json ├── next │ ├── pnpm-workspace.yaml │ ├── .npmrc │ ├── public │ │ ├── favicon.ico │ │ └── vercel.svg │ ├── styles │ │ ├── test.css │ │ ├── main.sass │ │ ├── main.scss │ │ ├── plain.css │ │ └── Home.module.css │ ├── pages │ │ ├── api │ │ │ └── hello.js │ │ ├── test.jsx │ │ ├── _app.js │ │ ├── layout.jsx │ │ └── index.jsx │ ├── next.config.js │ ├── windi.config.ts │ ├── package.json │ ├── .gitignore │ └── README.md ├── nuxt │ ├── assets │ │ ├── styles │ │ │ ├── windi.css │ │ │ ├── layout.sass │ │ │ └── global.css │ │ └── css │ │ │ ├── test.css │ │ │ └── main.scss │ ├── components │ │ ├── Foo.vue │ │ ├── StylusScoped.vue │ │ ├── SassScoped.vue │ │ ├── CssScoped.vue │ │ ├── ScssScoped.vue │ │ ├── PostcssScoped.vue │ │ ├── LessScoped.vue │ │ ├── Animation.vue │ │ └── HelloWorld.vue │ ├── plugins │ │ └── windicss.js │ ├── nuxt.config.js │ ├── windi.config.ts │ ├── package.json │ └── pages │ │ └── index.vue ├── icejs │ ├── src │ │ ├── global.css │ │ ├── app.tsx │ │ ├── routes.ts │ │ ├── typings.d.ts │ │ └── pages │ │ │ └── Home │ │ │ └── index.tsx │ ├── .stylelintignore │ ├── .prettierrc.js │ ├── .prettierignore │ ├── .stylelintrc.js │ ├── .eslintignore │ ├── build.json │ ├── .editorconfig │ ├── .eslintrc.js │ ├── public │ │ ├── index.html │ │ └── favicon.png │ ├── .gitignore │ ├── windi.config.ts │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── craco │ ├── public │ │ ├── robots.txt │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── index.html │ ├── windi.config.ts │ ├── src │ │ ├── setupTests.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── reportWebVitals.js │ │ ├── index.js │ │ ├── App.css │ │ ├── App.js │ │ └── logo.svg │ ├── .gitignore │ ├── craco.config.js │ ├── package.json │ └── README.md ├── vue2 │ ├── babel.config.js │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── assets │ │ │ ├── logo.png │ │ │ └── test.css │ │ ├── main.js │ │ ├── components │ │ │ ├── StylusScoped.vue │ │ │ ├── SassScoped.vue │ │ │ ├── CssScoped.vue │ │ │ ├── ScssScoped.vue │ │ │ ├── PostcssScoped.vue │ │ │ └── LessScoped.vue │ │ └── App.vue │ ├── .gitignore │ ├── README.md │ ├── vue.config.js │ ├── windi.config.ts │ └── package.json ├── vue3 │ ├── babel.config.js │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── assets │ │ │ ├── logo.png │ │ │ └── test.css │ │ ├── main.js │ │ ├── components │ │ │ ├── StylusScoped.vue │ │ │ ├── SassScoped.vue │ │ │ ├── CssScoped.vue │ │ │ ├── ScssScoped.vue │ │ │ ├── PostcssScoped.vue │ │ │ ├── LessScoped.vue │ │ │ └── HelloWorld.vue │ │ └── App.vue │ ├── vue.config.js │ ├── .gitignore │ ├── README.md │ ├── windi.config.ts │ └── package.json ├── vue-cli-next │ ├── babel.config.js │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── assets │ │ │ ├── logo.png │ │ │ └── test.css │ │ ├── components │ │ │ ├── Foo.vue │ │ │ ├── SassScoped.vue │ │ │ ├── StylusScoped.vue │ │ │ ├── CssScoped.vue │ │ │ ├── ScssScoped.vue │ │ │ ├── PostcssScoped.vue │ │ │ └── LessScoped.vue │ │ ├── main.js │ │ └── App.vue │ ├── vue.config.js │ ├── .gitignore │ ├── README.md │ ├── windi.config.ts │ └── package.json └── vue3-storybook │ ├── babel.config.js │ ├── public │ ├── favicon.ico │ └── index.html │ ├── src │ ├── assets │ │ ├── logo.png │ │ └── test.css │ ├── main.js │ ├── components │ │ ├── StylusScoped.vue │ │ ├── SassScoped.vue │ │ ├── CssScoped.vue │ │ ├── ScssScoped.vue │ │ ├── LessScoped.vue │ │ ├── PostcssScoped.vue │ │ ├── CssLang.stories.js │ │ └── HelloWorld.vue │ ├── stories │ │ ├── header.css │ │ ├── button.css │ │ ├── Header.stories.js │ │ ├── Page.stories.js │ │ ├── Button.stories.js │ │ ├── assets │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── code-brackets.svg │ │ │ ├── comments.svg │ │ │ ├── repo.svg │ │ │ ├── plugin.svg │ │ │ └── stackalt.svg │ │ ├── Button.vue │ │ ├── page.css │ │ ├── Header.vue │ │ ├── Page.vue │ │ └── Introduction.stories.mdx │ └── App.vue │ ├── vue.config.js │ ├── .storybook │ ├── preview.js │ └── main.js │ ├── .gitignore │ ├── README.md │ ├── windi.config.ts │ └── package.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── test.yml │ └── release.yml ├── test ├── fixtures │ ├── import-css-with-apply │ │ ├── styles │ │ │ ├── windi.css │ │ │ └── global.css │ │ ├── index.js │ │ ├── templates │ │ │ └── App.vue │ │ └── windi.config.ts │ ├── react-layers │ │ ├── index.js │ │ ├── windi.config.ts │ │ └── templates │ │ │ └── layout-layer.jsx │ ├── react │ │ ├── index.js │ │ ├── windi.config.ts │ │ └── templates │ │ │ ├── layout2.jsx │ │ │ └── layout.jsx │ ├── vue │ │ ├── stylesheets │ │ │ ├── main.sass │ │ │ ├── main.scss │ │ │ ├── main.less │ │ │ └── plain.css │ │ ├── index.js │ │ ├── windi.config.ts │ │ └── templates │ │ │ └── App.vue │ ├── vue-layers │ │ ├── stylesheets │ │ │ ├── main.sass │ │ │ ├── main.scss │ │ │ ├── main.less │ │ │ └── plain.css │ │ ├── windi.config.ts │ │ ├── index.js │ │ └── templates │ │ │ └── App.vue │ ├── vue-directives │ │ ├── stylesheets │ │ │ └── plain.css │ │ ├── index.js │ │ ├── windi.config.ts │ │ └── templates │ │ │ └── App.vue │ └── excluded-transform │ │ ├── windi.config.ts │ │ ├── index.js │ │ ├── node_modules_demo │ │ ├── my-package │ │ │ └── should-transform.css │ │ └── some-other-package │ │ │ └── should-not-transform.css │ │ └── templates │ │ └── App.vue ├── helpers │ ├── index.ts │ ├── getModuleSource.ts │ ├── reactWebpackCompiler.ts │ └── vueWebpackCompiler.ts ├── directives.test.ts ├── import-from-css-apply.test.ts ├── excluded-transform.test.ts ├── layers.test.ts ├── regex.test.ts └── tranform-template.test.ts ├── .eslintignore ├── src ├── core │ ├── dev-tools-update.ts │ ├── debug.ts │ ├── constants.ts │ ├── utils.ts │ └── server.ts ├── loaders │ ├── windicss-css.ts │ ├── dev-tools.ts │ ├── windicss-style-pitcher.ts │ ├── windicss-template.ts │ └── virtual-module.ts ├── types.ts └── runtime │ └── client.ts ├── .eslintrc.json ├── .editorconfig ├── .gitignore ├── vitest.config.ts ├── tsconfig.json ├── package.json └── README.md /example/umijs/mock/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/umijs/src/global.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/next/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [harlan-zw] 2 | -------------------------------------------------------------------------------- /example/nuxt/assets/styles/windi.css: -------------------------------------------------------------------------------- 1 | @import './global.css'; 2 | -------------------------------------------------------------------------------- /example/umijs/src/app.ts: -------------------------------------------------------------------------------- 1 | import 'windi.css'; 2 | import 'windi-devtools' 3 | -------------------------------------------------------------------------------- /example/next/.npmrc: -------------------------------------------------------------------------------- 1 | ignore-workspace-root-check=true 2 | shamefully-hoist=true 3 | -------------------------------------------------------------------------------- /test/fixtures/import-css-with-apply/styles/windi.css: -------------------------------------------------------------------------------- 1 | @import './global.css'; 2 | -------------------------------------------------------------------------------- /test/fixtures/react-layers/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/layout-layer.jsx') 2 | -------------------------------------------------------------------------------- /example/icejs/src/global.css: -------------------------------------------------------------------------------- 1 | body { 2 | -webkit-font-smoothing: antialiased; 3 | } 4 | -------------------------------------------------------------------------------- /example/nuxt/assets/styles/layout.sass: -------------------------------------------------------------------------------- 1 | #__layout 2 | background-color: #F6F6CE 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | *.snap 4 | test 5 | coverage 6 | example 7 | __snapshots__ 8 | -------------------------------------------------------------------------------- /test/fixtures/react/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/layout.jsx') 2 | require ('./templates/layout2.jsx') 3 | -------------------------------------------------------------------------------- /example/craco/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /example/icejs/.stylelintignore: -------------------------------------------------------------------------------- 1 | # 忽略目录 2 | build/ 3 | tests/ 4 | demo/ 5 | 6 | # node 覆盖率文件 7 | coverage/ 8 | -------------------------------------------------------------------------------- /example/umijs/src/pages/index.css: -------------------------------------------------------------------------------- 1 | 2 | .title { 3 | @apply bg-purple-500 text-5xl p-5 text-white; 4 | } 5 | -------------------------------------------------------------------------------- /example/vue2/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /example/vue3/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /example/craco/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/craco/public/favicon.ico -------------------------------------------------------------------------------- /example/craco/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/craco/public/logo192.png -------------------------------------------------------------------------------- /example/craco/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/craco/public/logo512.png -------------------------------------------------------------------------------- /example/next/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/next/public/favicon.ico -------------------------------------------------------------------------------- /example/vue-cli-next/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /example/vue2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue2/public/favicon.ico -------------------------------------------------------------------------------- /example/vue2/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue2/src/assets/logo.png -------------------------------------------------------------------------------- /example/vue3-storybook/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /example/vue3/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue3/public/favicon.ico -------------------------------------------------------------------------------- /example/vue3/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue3/src/assets/logo.png -------------------------------------------------------------------------------- /src/core/dev-tools-update.ts: -------------------------------------------------------------------------------- 1 | // This file is used to trigger the regeneration of the css for devtools, as it can be an empty file 2 | -------------------------------------------------------------------------------- /example/icejs/.prettierrc.js: -------------------------------------------------------------------------------- 1 | const { getPrettierConfig } = require('@iceworks/spec'); 2 | 3 | module.exports = getPrettierConfig('react'); 4 | -------------------------------------------------------------------------------- /example/umijs/.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | .umi-test 9 | -------------------------------------------------------------------------------- /test/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getModuleSource' 2 | export * from './vueWebpackCompiler' 3 | export * from './reactWebpackCompiler' 4 | -------------------------------------------------------------------------------- /example/icejs/.prettierignore: -------------------------------------------------------------------------------- 1 | build/ 2 | tests/ 3 | demo/ 4 | .ice/ 5 | coverage/ 6 | **/*-min.js 7 | **/*.min.js 8 | package-lock.json 9 | yarn.lock -------------------------------------------------------------------------------- /example/icejs/.stylelintrc.js: -------------------------------------------------------------------------------- 1 | const { getStylelintConfig } = require('@iceworks/spec');; 2 | 3 | module.exports = getStylelintConfig('react'); 4 | -------------------------------------------------------------------------------- /example/nuxt/components/Foo.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /example/vue-cli-next/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue-cli-next/public/favicon.ico -------------------------------------------------------------------------------- /example/vue-cli-next/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue-cli-next/src/assets/logo.png -------------------------------------------------------------------------------- /test/fixtures/import-css-with-apply/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/App.vue') 2 | require ('./styles/windi.css') 3 | 4 | require('windi.css') 5 | -------------------------------------------------------------------------------- /example/vue3-storybook/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue3-storybook/public/favicon.ico -------------------------------------------------------------------------------- /example/vue3-storybook/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windicss/windicss-webpack-plugin/HEAD/example/vue3-storybook/src/assets/logo.png -------------------------------------------------------------------------------- /example/vue3/src/main.js: -------------------------------------------------------------------------------- 1 | import {createApp} from 'vue' 2 | import App from './App.vue' 3 | import 'windi.css' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/Foo.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/main.js: -------------------------------------------------------------------------------- 1 | import {createApp} from 'vue' 2 | import App from './App.vue' 3 | import 'windi.css' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /example/icejs/.eslintignore: -------------------------------------------------------------------------------- 1 | # 忽略目录 2 | build/ 3 | tests/ 4 | demo/ 5 | .ice/ 6 | 7 | # node 覆盖率文件 8 | coverage/ 9 | 10 | # 忽略文件 11 | **/*-min.js 12 | **/*.min.js 13 | -------------------------------------------------------------------------------- /example/next/styles/test.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | @apply fixed top-0 left-0 right-0 bg-white shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply p-10 bg-blue-200; 8 | } 9 | -------------------------------------------------------------------------------- /example/nuxt/assets/css/test.css: -------------------------------------------------------------------------------- 1 | nav { 2 | @apply fixed top-0 left-0 right-0 bg-white shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply pt-10 bg-blue-250; 8 | } 9 | -------------------------------------------------------------------------------- /example/nuxt/plugins/windicss.js: -------------------------------------------------------------------------------- 1 | import 'virtual:windi-base.css' 2 | import 'virtual:windi-components.css' 3 | import 'virtual:windi-utilities.css' 4 | import 'virtual:windi-devtools' 5 | -------------------------------------------------------------------------------- /example/next/styles/main.sass: -------------------------------------------------------------------------------- 1 | .sass-global 2 | @apply "bg-orange-400 text-white p-4 w-1/4 transition hover:(bg-orange-900 text-orange-100)" 3 | h2 4 | @apply "font-bold text-sm" 5 | -------------------------------------------------------------------------------- /example/vue2/src/assets/test.css: -------------------------------------------------------------------------------- 1 | nav { 2 | @apply fixed top-0 left-0 right-0 bg-red-200 shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply pt-10 bg-blue-250; 8 | } 9 | -------------------------------------------------------------------------------- /example/vue3/src/assets/test.css: -------------------------------------------------------------------------------- 1 | nav { 2 | @apply fixed top-0 left-0 right-0 bg-red-200 shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply pt-10 bg-blue-250; 8 | } 9 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/assets/test.css: -------------------------------------------------------------------------------- 1 | nav { 2 | @apply fixed top-0 left-0 right-0 bg-red-200 shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply pt-10 bg-blue-250; 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/vue/stylesheets/main.sass: -------------------------------------------------------------------------------- 1 | .sass-global 2 | @apply bg-orange-400 text-white p-4 w-1/4 transition hover:(bg-orange-900 text-orange-100) 3 | h2 4 | @apply font-bold text-sm 5 | -------------------------------------------------------------------------------- /example/next/styles/main.scss: -------------------------------------------------------------------------------- 1 | .scss-global { 2 | @apply bg-blue-400 text-white p-4 w-1/4 transition hover:(bg-blue-900 text-blue-100); 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/assets/test.css: -------------------------------------------------------------------------------- 1 | nav { 2 | @apply fixed top-0 left-0 right-0 bg-red-200 shadow shadow-2xl; 3 | padding: 10px; 4 | } 5 | 6 | html { 7 | @apply pt-10 bg-blue-250; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/debug.ts: -------------------------------------------------------------------------------- 1 | import _debug from 'debug' 2 | import { NAME } from './constants' 3 | 4 | export default { 5 | plugin: _debug(`${NAME}:plugin`), 6 | loader: _debug(`${NAME}:loader`), 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/stylesheets/main.sass: -------------------------------------------------------------------------------- 1 | .sass-global 2 | @apply bg-orange-400 text-white p-4 w-1/4 transition hover:(bg-orange-900 text-orange-100) 3 | h2 4 | @apply font-bold text-sm 5 | -------------------------------------------------------------------------------- /example/icejs/build.json: -------------------------------------------------------------------------------- 1 | { 2 | "webpackPlugins": { 3 | "windicss-webpack-plugin": {} 4 | }, 5 | "eslint": { 6 | "exclude": ["**/node_modules/**", "**/virtual:windi-devtools*"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example/nuxt/assets/css/main.scss: -------------------------------------------------------------------------------- 1 | .scss-global { 2 | @apply bg-green-400 text-white p-4 w-1/4 transition hover:(bg-green-900 text-blue-100); 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/next/pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default (request, res) => { 4 | res.status(200).json({name: 'John Doe'}) 5 | } 6 | -------------------------------------------------------------------------------- /example/next/styles/plain.css: -------------------------------------------------------------------------------- 1 | .css-global { 2 | @apply bg-yellow-400 text-white p-4 w-1/4 transition hover:(bg-yellow-900 text-yellow-100); 3 | } 4 | .css-global h2 { 5 | @apply font-bold text-sm; 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/vue/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | .scss-global { 2 | @apply bg-blue-400 text-white p-4 w-1/4 transition hover:(bg-blue-900 text-blue-100); 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | .scss-global { 2 | @apply bg-blue-400 text-white p-4 w-1/4 transition hover:(bg-blue-900 text-blue-100); 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/vue/stylesheets/main.less: -------------------------------------------------------------------------------- 1 | .less-global { 2 | @apply " bg-purple-400 text-white p-4 w-1/4 transition hover:(bg-purple-900 text-purple-100)"; 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "extends": "@antfu", 6 | "rules": { 7 | "@typescript-eslint/no-var-requires": "off", 8 | "no-cond-assign": "off" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/vue/stylesheets/plain.css: -------------------------------------------------------------------------------- 1 | .global-css { 2 | @apply bg-yellow-400 text-white p-4 w-1/4 transition hover:(bg-yellow-900 text-yellow-100); 3 | } 4 | .global-css h2 { 5 | @apply font-bold text-sm; 6 | } 7 | -------------------------------------------------------------------------------- /example/next/pages/test.jsx: -------------------------------------------------------------------------------- 1 | export default function Test() { 2 | return ( 3 |
4 |

This is the test page

5 | return home 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /example/umijs/README.md: -------------------------------------------------------------------------------- 1 | # umi project 2 | 3 | ## Getting Started 4 | 5 | Install dependencies, 6 | 7 | ```bash 8 | $ yarn 9 | ``` 10 | 11 | Start the dev server, 12 | 13 | ```bash 14 | $ yarn start 15 | ``` 16 | -------------------------------------------------------------------------------- /test/fixtures/vue-directives/stylesheets/plain.css: -------------------------------------------------------------------------------- 1 | @layer components { 2 | .bar { 3 | @apply bg-pink-100; 4 | } 5 | 6 | @screen md { 7 | .bar { 8 | background: red; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/stylesheets/main.less: -------------------------------------------------------------------------------- 1 | .less-global { 2 | @apply " bg-purple-400 text-white p-4 w-1/4 transition hover:(bg-purple-900 text-purple-100)"; 3 | h2 { 4 | @apply font-bold text-sm; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/stylesheets/plain.css: -------------------------------------------------------------------------------- 1 | .global-css { 2 | @apply bg-yellow-400 text-white p-4 w-1/4 transition hover:(bg-yellow-900 text-yellow-100); 3 | } 4 | .global-css h2 { 5 | @apply font-bold text-sm; 6 | } 7 | -------------------------------------------------------------------------------- /example/vue3/vue.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('windicss-webpack-plugin') 2 | 3 | module.exports = { 4 | configureWebpack: { 5 | plugins: [ 6 | new WindiCSSWebpackPlugin, 7 | ], 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/vue-directives/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/App.vue') 2 | require ('./stylesheets/plain.css') 3 | 4 | require('virtual:windi-base.css') 5 | require('virtual:windi-components.css') 6 | require('virtual:windi-utilities.css') 7 | -------------------------------------------------------------------------------- /example/vue2/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import i18n from './i18n' 4 | 5 | Vue.config.productionTip = false 6 | 7 | new Vue({ 8 | i18n, 9 | render: h => h(App) 10 | }).$mount('#app') 11 | -------------------------------------------------------------------------------- /test/fixtures/import-css-with-apply/styles/global.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | @apply text-4xl; 3 | } 4 | h2 { 5 | @apply text-3xl; 6 | } 7 | h3 { 8 | @apply text-2xl; 9 | } 10 | h4 { 11 | background-color: theme("colors.blue.500"); 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/vue/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/App.vue') 2 | require ('windi.css') 3 | require ('./stylesheets/main.less') 4 | require ('./stylesheets/main.scss') 5 | require ('./stylesheets/main.sass') 6 | require ('./stylesheets/plain.css') 7 | -------------------------------------------------------------------------------- /example/vue-cli-next/vue.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('windicss-webpack-plugin') 2 | 3 | module.exports = { 4 | configureWebpack: { 5 | plugins: [ 6 | new WindiCSSWebpackPlugin, 7 | ], 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /example/vue3-storybook/vue.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('windicss-webpack-plugin') 2 | 3 | module.exports = { 4 | configureWebpack: { 5 | plugins: [ 6 | new WindiCSSWebpackPlugin, 7 | ], 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /example/craco/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['**/*.{jsx,js,css,html}'], 6 | exclude: ['node_modules', '.git', '.next/**/*'], 7 | }, 8 | }) 9 | -------------------------------------------------------------------------------- /example/umijs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 80, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/import-css-with-apply/templates/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /test/fixtures/react/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['templates/**/*.{vue,html,jsx,tsx}', 'stylesheets/**/*.{less,sass,scss,css}', ], 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/vue/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['templates/**/*.{vue,html,jsx,tsx}', 'stylesheets/**/*.{less,sass,scss,css}', ], 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['templates/**/*.{vue,html,jsx,tsx}', 'stylesheets/**/*.{less,sass,scss,css}', ], 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /example/icejs/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { runApp, IAppConfig } from 'ice'; 2 | 3 | import 'windi.css'; 4 | import 'windi-devtools'; 5 | 6 | const appConfig: IAppConfig = { 7 | app: { 8 | rootId: 'ice-container', 9 | }, 10 | }; 11 | 12 | runApp(appConfig); 13 | -------------------------------------------------------------------------------- /example/icejs/src/routes.ts: -------------------------------------------------------------------------------- 1 | import { IRouterConfig } from 'ice'; 2 | import Home from '@/pages/Home'; 3 | 4 | const routerConfig: IRouterConfig[] = [ 5 | { 6 | path: '/', 7 | component: Home, 8 | }, 9 | ]; 10 | 11 | export default routerConfig; 12 | -------------------------------------------------------------------------------- /example/nuxt/assets/styles/global.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | @apply text-4xl; 3 | } 4 | h2 { 5 | @apply text-3xl; 6 | } 7 | h3 { 8 | @apply text-2xl; 9 | } 10 | 11 | .test-global-import-replace { 12 | @apply bg-green-500 text-white inline-block p-3 m-5; 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/react-layers/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['templates/**/*.{vue,html,jsx,tsx}', 'stylesheets/**/*.{less,sass,scss,css}', ], 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/vue-directives/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['templates/**/*.{vue,html,jsx,tsx}', 'stylesheets/**/*.{less,sass,scss,css}', ], 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/excluded-transform/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['index.js', 'templates/*.vue'], 6 | exclude: ['node_modules_demo'], 7 | } 8 | }) 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /example/icejs/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /test/fixtures/import-css-with-apply/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@windicss/plugin-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['index.js', 'templates/*.vue'], 6 | exclude: ['node_modules_demo'], 7 | } 8 | }) 9 | 10 | -------------------------------------------------------------------------------- /example/craco/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /example/vue3-storybook/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import 'windi.css' 2 | 3 | export const parameters = { 4 | actions: { argTypesRegex: "^on[A-Z].*" }, 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /example/craco/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /example/next/next.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('windicss-webpack-plugin') 2 | 3 | module.exports = { 4 | webpack: config => { 5 | config.plugins.push(new WindiCSSWebpackPlugin) 6 | return config 7 | }, 8 | eslint: { 9 | ignoreDuringBuilds: true, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /example/umijs/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.less'; 3 | declare module '*.png'; 4 | declare module '*.svg' { 5 | export function ReactComponent( 6 | props: React.SVGProps, 7 | ): React.ReactElement; 8 | const url: string; 9 | export default url; 10 | } 11 | -------------------------------------------------------------------------------- /example/icejs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const { getESLintConfig } = require('@iceworks/spec'); 2 | 3 | // https://www.npmjs.com/package/@iceworks/spec 4 | module.exports = getESLintConfig('react-ts', { 5 | rules: { 6 | 'react/jsx-filename-extension': 0, 7 | '@typescript-eslint/explicit-function-return-type': 0, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /example/next/pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/test.css' 2 | import '../styles/plain.css' 3 | import '../styles/main.sass' 4 | import '../styles/main.scss' 5 | import 'windi.css' 6 | import 'windi-devtools' 7 | 8 | function MyApp({Component, pageProps}) { 9 | return 10 | } 11 | 12 | export default MyApp 13 | -------------------------------------------------------------------------------- /example/umijs/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /test/fixtures/excluded-transform/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/App.vue') 2 | require ('./node_modules_demo/my-package/should-transform.css') 3 | require ('./node_modules_demo/some-other-package/should-not-transform.css') 4 | 5 | require('virtual:windi-base.css') 6 | require('virtual:windi-components.css') 7 | require('virtual:windi-utilities.css') 8 | -------------------------------------------------------------------------------- /example/nuxt/components/StylusScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue2/.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 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /test/fixtures/vue-layers/index.js: -------------------------------------------------------------------------------- 1 | require ('./templates/App.vue') 2 | require ('./stylesheets/main.less') 3 | require ('./stylesheets/main.scss') 4 | require ('./stylesheets/main.sass') 5 | require ('./stylesheets/plain.css') 6 | 7 | require('virtual:windi-base.css') 8 | require('virtual:windi-components.css') 9 | require('virtual:windi-utilities.css') 10 | -------------------------------------------------------------------------------- /example/nuxt/components/SassScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue-cli-next/.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 | -------------------------------------------------------------------------------- /example/vue2/src/components/StylusScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue3/src/components/StylusScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue2/src/components/SassScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue3-storybook/.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 | -------------------------------------------------------------------------------- /example/vue3/src/components/SassScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/nuxt/components/CssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/SassScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/StylusScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/StylusScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/nuxt/components/ScssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue2/src/components/CssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue2/src/components/ScssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/SassScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 13 | -------------------------------------------------------------------------------- /example/vue3/src/components/CssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3/src/components/ScssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/icejs/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | icejs simple app 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /example/nuxt/components/PostcssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/CssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/nuxt/components/LessScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/ScssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue2/src/components/PostcssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/CssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/ScssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3/src/components/PostcssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/umijs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /yarn.lock 8 | /package-lock.json 9 | 10 | # production 11 | /dist 12 | 13 | # misc 14 | .DS_Store 15 | 16 | # umi 17 | /src/.umi 18 | /src/.umi-production 19 | /src/.umi-test 20 | /.env.local 21 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/PostcssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue2/src/components/LessScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/LessScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3/src/components/LessScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/components/LessScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/PostcssScoped.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /example/icejs/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.scss' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | 6 | declare module '*.module.less' { 7 | const classes: { [key: string]: string }; 8 | export default classes; 9 | } 10 | 11 | declare module '*.module.css' { 12 | const classes: { [key: string]: string }; 13 | export default classes; 14 | } 15 | -------------------------------------------------------------------------------- /example/icejs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # production 7 | build/ 8 | dist/ 9 | tmp/ 10 | lib/ 11 | 12 | # misc 13 | .idea/ 14 | .happypack 15 | .DS_Store 16 | *.swp 17 | *.dia~ 18 | .ice 19 | .vscode 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | index.module.scss.d.ts 25 | -------------------------------------------------------------------------------- /example/next/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['**/*.{jsx,css}'], 6 | exclude: ['node_modules', '.git', '.next/**/*'], 7 | }, 8 | attributify: true, 9 | shortcuts: { 10 | btn: 'rounded-lg border border-gray-300 text-gray-100 bg-blue-500 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /example/craco/.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 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /example/vue3-storybook/.storybook/main.js: -------------------------------------------------------------------------------- 1 | const WindiCSS = require('../../..') 2 | 3 | module.exports = { 4 | "stories": [ 5 | "../src/**/*.stories.mdx", 6 | "../src/**/*.stories.@(js|jsx|ts|tsx)" 7 | ], 8 | "addons": [ 9 | "@storybook/addon-links", 10 | "@storybook/addon-essentials" 11 | ], 12 | webpackFinal: (config) => { 13 | config.plugins.push(new WindiCSS()); 14 | return config; 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /example/vue3/README.md: -------------------------------------------------------------------------------- 1 | # vue3 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /example/vue2/README.md: -------------------------------------------------------------------------------- 1 | # vue-cli 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /example/craco/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /example/vue-cli-next/README.md: -------------------------------------------------------------------------------- 1 | # vue-cli 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /example/vue2/vue.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('windicss-webpack-plugin') 2 | 3 | module.exports = { 4 | 5 | pluginOptions: { 6 | i18n: { 7 | locale: 'en', 8 | fallbackLocale: 'en', 9 | localeDir: 'locales', 10 | enableInSFC: true, 11 | enableBridge: false 12 | } 13 | }, 14 | configureWebpack: { 15 | plugins: [ 16 | new WindiCSSWebpackPlugin, 17 | ], 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /example/vue3-storybook/README.md: -------------------------------------------------------------------------------- 1 | # vue3 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /example/craco/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | .DS_Store 3 | 4 | .idea 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | 11 | # Dependency directories 12 | node_modules/ 13 | 14 | # Optional npm cache directory 15 | .npm 16 | 17 | # Optional REPL history 18 | .node_repl_history 19 | 20 | # Output of 'npm pack' 21 | *.tgz 22 | 23 | # Jest coverage data 24 | coverage 25 | 26 | # Distribution files 27 | dist 28 | 29 | .nuxt 30 | .next 31 | .env 32 | 33 | .umi 34 | -------------------------------------------------------------------------------- /example/icejs/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers'; 2 | 3 | export default defineConfig({ 4 | preflight: false, 5 | extract: { 6 | include: ['**/*.{html,jsx,tsx}'], 7 | exclude: ['.git', '.ice', 'node_modules', 'build'], 8 | }, 9 | attributify: true, 10 | shortcuts: { 11 | btn: 'rounded-lg border border-gray-300 text-gray-100 bg-blue-500 px-4 py-2 m-2 inline-block hover:shadow cursor-pointer', 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /example/nuxt/nuxt.config.js: -------------------------------------------------------------------------------- 1 | import WindiCSSWebpackPlugin from 'windicss-webpack-plugin' 2 | 3 | module.exports = { 4 | css: [ 5 | '@/assets/css/test.css', 6 | '@/assets/css/main.scss', 7 | '@/assets/styles/windi.css', 8 | '@/assets/styles/layout.sass', 9 | ], 10 | plugins: [ 11 | '@/plugins/windicss.js', 12 | ], 13 | components: true, 14 | build: { 15 | plugins: [ 16 | new WindiCSSWebpackPlugin, 17 | ], 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /test/helpers/getModuleSource.ts: -------------------------------------------------------------------------------- 1 | export function getModuleSource (id, stats) { 2 | const { modules } = stats.toJson({ source: true }); 3 | const module = modules.find((m) => m.name.indexOf(id) > -1); 4 | 5 | if (!module) { 6 | throw new Error('Failed to find module ' + id) 7 | } 8 | 9 | let { source } = module; 10 | 11 | // Todo remove after drop webpack@4 support 12 | source = source.replace(/\?\?.*!/g, "??[ident]!"); 13 | 14 | return source; 15 | }; 16 | -------------------------------------------------------------------------------- /example/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@zeit/next-less": "^1.0.1", 12 | "less": "^4.1.1", 13 | "next": "12.1.6", 14 | "react": "18.1.0", 15 | "react-dom": "18.1.0", 16 | "sass": "^1.35.1", 17 | "windicss-webpack-plugin": "link:../../" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { resolve } from 'path' 3 | import { defineConfig, AliasOptions } from 'vite' 4 | 5 | const r = (p: string) => resolve(__dirname, p) 6 | 7 | export const alias: AliasOptions = { 8 | 'windicss-webpack-plugin': r('./src/'), 9 | } 10 | 11 | export default defineConfig({ 12 | test: { 13 | testTimeout: 1200000, 14 | include: ['test/**.test.ts'] 15 | }, 16 | resolve: { 17 | alias, 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/loaders/windicss-css.ts: -------------------------------------------------------------------------------- 1 | import type { loader } from 'webpack' 2 | import { transformCSS } from '../core/utils' 3 | 4 | function WindicssCss( 5 | this: loader.LoaderContext, 6 | source: string, 7 | ): string { 8 | if (!this._compiler) 9 | return source 10 | 11 | this.cacheable(true) 12 | // @ts-expect-error untyped 13 | const service = this._compiler.$windi 14 | 15 | if (!service) 16 | return source 17 | 18 | return transformCSS(service, source, this.resource) 19 | } 20 | 21 | export default WindicssCss 22 | -------------------------------------------------------------------------------- /example/next/.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 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /example/umijs/.umirc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'umi'; 2 | import WindiCSSWebpackPlugin from 'windicss-webpack-plugin' 3 | 4 | export default defineConfig({ 5 | nodeModulesTransform: { 6 | type: 'none', 7 | }, 8 | routes: [ 9 | { path: '/', component: '@/pages/index' }, 10 | ], 11 | // must be disabled 12 | // see: https://github.com/umijs/umi/issues/7303 13 | mfsu: false, 14 | fastRefresh: {}, 15 | chainWebpack(config : any) { 16 | config 17 | .plugin('windicss') 18 | .use(WindiCSSWebpackPlugin); 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /example/vue2/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['src/**/*.{vue,css}', 'public/**/*.html'] 6 | }, 7 | attributify: true, 8 | darkMode: 'class', 9 | shortcuts: { 10 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | theme: { 13 | extend: { 14 | colors: { 15 | teal: { 16 | 100: '#453', 17 | 900: '#216b6b', 18 | }, 19 | }, 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /example/vue3/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['src/**/*.{vue,css}', 'public/**/*.html'] 6 | }, 7 | attributify: true, 8 | darkMode: 'class', 9 | shortcuts: { 10 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | theme: { 13 | extend: { 14 | colors: { 15 | teal: { 16 | 100: '#453', 17 | 900: '#216b6b', 18 | }, 19 | }, 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /test/fixtures/excluded-transform/node_modules_demo/my-package/should-transform.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --header-height: theme('spacing.14'); 3 | --docs-scroll-margin-block: calc(var(--header-height) + 4rem); 4 | --blogpost-scroll-margin-block: calc(var(--header-height)); 5 | } 6 | 7 | @screen md { 8 | :root { 9 | --header-height: theme('spacing.18'); 10 | --blogpost-scroll-margin-block: calc(var(--header-height) - 0.5rem); 11 | } 12 | } 13 | 14 | @screen xl { 15 | :root { 16 | --docs-scroll-margin-block: calc(var(--header-height) + 1rem); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/umijs/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | exclude: ['node_modules', '.git', 'dist', 'mock', '.umi'], 6 | }, 7 | attributify: true, 8 | darkMode: 'class', 9 | shortcuts: { 10 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | theme: { 13 | extend: { 14 | colors: { 15 | teal: { 16 | 100: '#453', 17 | 900: '#216b6b', 18 | }, 19 | }, 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /example/vue-cli-next/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['src/**/*.{vue,css}', 'public/**/*.html'] 6 | }, 7 | attributify: true, 8 | darkMode: 'class', 9 | shortcuts: { 10 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | theme: { 13 | extend: { 14 | colors: { 15 | teal: { 16 | 100: '#453', 17 | 900: '#216b6b', 18 | }, 19 | }, 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /example/vue3-storybook/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['src/**/*.{vue,css}', 'public/**/*.html'] 6 | }, 7 | attributify: true, 8 | darkMode: 'class', 9 | shortcuts: { 10 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 11 | }, 12 | theme: { 13 | extend: { 14 | colors: { 15 | teal: { 16 | 100: '#453', 17 | 900: '#216b6b', 18 | }, 19 | }, 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /example/craco/craco.config.js: -------------------------------------------------------------------------------- 1 | const WindiCSSWebpackPlugin = require('../../') 2 | 3 | module.exports = { 4 | eslint: { 5 | pluginOptions: config => { 6 | config.exclude = ['**/node_modules/**', '**/virtual:windi-devtools*'] 7 | return config; 8 | }, 9 | }, 10 | webpack: { 11 | plugins: { 12 | add: [ 13 | new WindiCSSWebpackPlugin({ 14 | virtualModulePath: 'src', 15 | server: { 16 | port: 9999, 17 | host: 'localhost' 18 | } 19 | }) 20 | ], 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/excluded-transform/node_modules_demo/some-other-package/should-not-transform.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --header-height: theme('spacing.14'); 3 | --docs-scroll-margin-block: calc(var(--header-height) + 4rem); 4 | --blogpost-scroll-margin-block: calc(var(--header-height)); 5 | } 6 | 7 | @screen md { 8 | :root { 9 | --header-height: theme('spacing.18'); 10 | --blogpost-scroll-margin-block: calc(var(--header-height) - 0.5rem); 11 | } 12 | } 13 | 14 | @screen xl { 15 | :root { 16 | --docs-scroll-margin-block: calc(var(--header-height) + 1rem); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/nuxt/windi.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'windicss/helpers' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | include: ['**/*.{vue,js,ts}'], 6 | exclude: ['node_modules', '.git', 'dist', 'mock', '.umi'], 7 | }, 8 | attributify: true, 9 | darkMode: 'class', 10 | shortcuts: { 11 | btn: 'rounded border border-gray-300 text-gray-600 px-4 py-2 m-2 inline-block hover:shadow', 12 | }, 13 | theme: { 14 | extend: { 15 | colors: { 16 | teal: { 17 | 100: '#453', 18 | 900: '#216b6b', 19 | }, 20 | }, 21 | }, 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/header.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | border-bottom: 1px solid rgba(0, 0, 0, 0.1); 4 | padding: 15px 20px; 5 | display: flex; 6 | align-items: center; 7 | justify-content: space-between; 8 | } 9 | 10 | svg { 11 | display: inline-block; 12 | vertical-align: top; 13 | } 14 | 15 | h1 { 16 | font-weight: 900; 17 | font-size: 20px; 18 | line-height: 1; 19 | margin: 6px 0 6px 10px; 20 | display: inline-block; 21 | vertical-align: top; 22 | } 23 | 24 | button + button { 25 | margin-left: 10px; 26 | } 27 | -------------------------------------------------------------------------------- /example/craco/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Clone repository '...' 16 | 2. Run '....' 17 | 3. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /example/umijs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.css'; 3 | 4 | export default function Page() { 5 | return ( 6 |
7 |

WindiCSS Umi example

8 |
9 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi culpa dicta in laboriosam molestiae nesciunt pariatur perferendis perspiciatis placeat, porro quaerat qui quis rem similique sint veniam veritatis. Accusamus, sequi?

10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /test/directives.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { getModuleSource, vueWebpackCompiler } from './helpers' 3 | 4 | describe("Directives test", function() { 5 | 6 | it('should render vue', done => { 7 | const compiler = vueWebpackCompiler('vue-directives') 8 | compiler.run((err, stats) => { 9 | expect(stats.compilation.errors).toStrictEqual([]) 10 | const windiComponents = getModuleSource('virtual:windi-components.css', stats) 11 | expect(windiComponents).toContain('.bar') 12 | expect(windiComponents).toMatchSnapshot('windi components') 13 | 14 | done(err) 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /example/craco/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import './virtual:windi.css' 7 | import './virtual:windi-devtools' 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | 16 | // If you want to start measuring performance in your app, pass a function 17 | // to log results (for example: reportWebVitals(console.log)) 18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 19 | reportWebVitals(); 20 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/CssLang.stories.js: -------------------------------------------------------------------------------- 1 | import CssScoped from './CssScoped.vue'; 2 | 3 | export default { 4 | title: 'Example/CSS Variants', 5 | }; 6 | 7 | export const ScopedCSS = () => ({ 8 | components: { CssScoped }, 9 | template: '', 10 | }); 11 | 12 | export const ScopedPostCSS = () => ({ 13 | template: '\n' + 20 | ' Attributify Mode\n' + 21 | ' ', 22 | }); 23 | -------------------------------------------------------------------------------- /test/import-from-css-apply.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { getModuleSource, vueWebpackCompiler } from './helpers' 3 | 4 | describe("@import css with @apply", function() { 5 | 6 | it('should render vue', done => { 7 | const compiler = vueWebpackCompiler('import-css-with-apply', ) 8 | compiler.run((err, stats) => { 9 | expect(stats.compilation.errors).toStrictEqual([]) 10 | 11 | const toNotTransformCss = getModuleSource('global.css', stats) 12 | expect(toNotTransformCss).not.toContain('@apply') 13 | expect(toNotTransformCss).toMatchSnapshot('@apply') 14 | 15 | done(err) 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /example/vue3/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/nuxt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "nuxt": "^2.15.8", 8 | "pug": "^3.0.2", 9 | "pug-loader": "^2.4.0", 10 | "sass": "^1.32.12", 11 | "sass-loader": "^10" 12 | }, 13 | "scripts": { 14 | "dev": "nuxt", 15 | "analysis": "windicss-analysis" 16 | }, 17 | "devDependencies": { 18 | "fibers": "^5.0.0", 19 | "less": "^4.1.1", 20 | "less-loader": "^7", 21 | "pug-plain-loader": "^1.1.0", 22 | "stylus": "^0.54.8", 23 | "stylus-loader": "^3", 24 | "windicss-analysis": "^0.0.17", 25 | "windicss-webpack-plugin": "file:../../" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/vue-cli-next/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/vue3-storybook/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /example/vue2/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/next/pages/layout.jsx: -------------------------------------------------------------------------------- 1 | export default function Layout({ title, children }) { 2 | return ( 3 |
4 | {children} 5 | 15 |
16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "lib": [ 6 | "ES2019", 7 | "dom" 8 | ], 9 | "module": "commonjs", 10 | "target": "ES2019", 11 | "strict": true, 12 | "esModuleInterop": true, 13 | "skipLibCheck": true, 14 | "moduleResolution": "node", 15 | "resolveJsonModule": true, 16 | "noUnusedLocals": true, 17 | "strictNullChecks": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "paths": { 20 | "windicss-webpack-plugin": ["./src/plugin.ts"] 21 | } 22 | }, 23 | "include": [ 24 | "src" 25 | ], 26 | "exclude": [ 27 | "example/**", 28 | "**/dist/**", 29 | "**/node_modules/**" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /example/craco/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/craco/src/App.js: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | import './App.css'; 3 | 4 | function App() { 5 | return ( 6 |
7 |
8 | logo 9 |

10 | Edit src/App.js and save to reload. 11 |

12 | 18 | Learn React 19 | 20 |
21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /example/umijs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "importHelpers": true, 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "sourceMap": true, 10 | "baseUrl": "./", 11 | "strict": true, 12 | "paths": { 13 | "@/*": ["src/*"], 14 | "@@/*": ["src/.umi/*"] 15 | }, 16 | "allowSyntheticDefaultImports": true 17 | }, 18 | "include": [ 19 | "mock/**/*", 20 | "src/**/*", 21 | "config/**/*", 22 | ".umirc.ts", 23 | "typings.d.ts" 24 | ], 25 | "exclude": [ 26 | "node_modules", 27 | "lib", 28 | "es", 29 | "dist", 30 | "typings", 31 | "**/__test__", 32 | "test", 33 | "docs", 34 | "tests" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/button.css: -------------------------------------------------------------------------------- 1 | .storybook-button { 2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | font-weight: 700; 4 | border: 0; 5 | border-radius: 3em; 6 | cursor: pointer; 7 | display: inline-block; 8 | line-height: 1; 9 | } 10 | .storybook-button--primary { 11 | color: white; 12 | background-color: #1ea7fd; 13 | } 14 | .storybook-button--secondary { 15 | color: #333; 16 | background-color: transparent; 17 | box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; 18 | } 19 | .storybook-button--small { 20 | font-size: 12px; 21 | padding: 10px 16px; 22 | } 23 | .storybook-button--medium { 24 | font-size: 14px; 25 | padding: 11px 20px; 26 | } 27 | .storybook-button--large { 28 | font-size: 16px; 29 | padding: 12px 24px; 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/react/templates/layout2.jsx: -------------------------------------------------------------------------------- 1 | import 'virtual:windi.css' 2 | 3 | export default function Layout({ title, children }) { 4 | return ( 5 |
6 | 7 | {title} 8 | 9 | {children} 10 | 20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /test/fixtures/react/templates/layout.jsx: -------------------------------------------------------------------------------- 1 | import 'virtual:windi.css' 2 | 3 | export default function Layout({ title, children }) { 4 | return ( 5 |
6 | 7 | {title} 8 | 9 | {children} 10 | 20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Header.stories.js: -------------------------------------------------------------------------------- 1 | import MyHeader from './Header.vue'; 2 | 3 | export default { 4 | title: 'Example/Header', 5 | component: MyHeader, 6 | }; 7 | 8 | const Template = (args) => ({ 9 | // Components used in your story `template` are defined in the `components` object 10 | components: { MyHeader }, 11 | // The story's `args` need to be mapped into the template through the `setup()` method 12 | setup() { 13 | // Story args can be spread into the returned object 14 | return { ...args }; 15 | }, 16 | // Then, the spread values can be accessed directly in the template 17 | template: '', 18 | }); 19 | 20 | export const LoggedIn = Template.bind({}); 21 | LoggedIn.args = { 22 | user: {}, 23 | }; 24 | 25 | export const LoggedOut = Template.bind({}); 26 | LoggedOut.args = { 27 | user: null, 28 | }; 29 | -------------------------------------------------------------------------------- /test/fixtures/react-layers/templates/layout-layer.jsx: -------------------------------------------------------------------------------- 1 | import 'virtual:windi-base.css' 2 | import 'virtual:windi-components.css' 3 | import 'virtual:windi-utilities.css' 4 | 5 | export default function Layout({ title, children }) { 6 | return ( 7 |
8 | 9 | {title} 10 | 11 | {children} 12 | 22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Page.stories.js: -------------------------------------------------------------------------------- 1 | import MyPage from './Page.vue'; 2 | import * as HeaderStories from './Header.stories'; 3 | 4 | export default { 5 | title: 'Example/Page', 6 | component: MyPage, 7 | }; 8 | 9 | const Template = (args) => ({ 10 | // Components used in your story `template` are defined in the `components` object 11 | components: { MyPage }, 12 | // The story's `args` need to be mapped into the template through the `setup()` method 13 | setup() { 14 | // Story args can be mapped to keys in the returned object 15 | return { user: args.user }; 16 | }, 17 | // Then, those values can be accessed directly in the template 18 | template: '', 19 | }); 20 | 21 | export const LoggedIn = Template.bind({}); 22 | LoggedIn.args = { 23 | ...HeaderStories.LoggedIn.args, 24 | }; 25 | 26 | export const LoggedOut = Template.bind({}); 27 | LoggedOut.args = { 28 | ...HeaderStories.LoggedOut.args, 29 | }; 30 | -------------------------------------------------------------------------------- /src/core/constants.ts: -------------------------------------------------------------------------------- 1 | export const NAME = 'windicss-webpack-plugin' 2 | export const MODULE_ID = 'windi.css' 3 | export const MODULE_ID_VIRTUAL_TEST = /virtual:windi-?(.*?)\.css/ 4 | export const MODULE_ID_VIRTUAL_PREFIX = 'virtual:windi' 5 | export const MODULE_ID_VIRTUAL_MODULES = [ 6 | `${MODULE_ID_VIRTUAL_PREFIX}.css`, 7 | `${MODULE_ID_VIRTUAL_PREFIX}-base.css`, 8 | `${MODULE_ID_VIRTUAL_PREFIX}-utilities.css`, 9 | `${MODULE_ID_VIRTUAL_PREFIX}-components.css`, 10 | ] 11 | 12 | export const HAS_DIRECTIVE_TEST = /@(apply|variants|screen|layer)\s/ 13 | export const HAS_THEME_FUNCTION_TEST = /theme\(.*?\)/ 14 | export const DEVTOOLS_MODULE_ID = 'windi-devtools' 15 | export const DEVTOOLS_VIRTUAL_MODULE_ID = 'virtual:windi-devtools' 16 | export const DEVTOOLS_VIRTUAL_MODULE = 'virtual:windi-devtools.js' 17 | export const DEVTOOLS_POST_PATH = '/@windicss-devtools-update' 18 | export const DEFAULT_SERVER_HOST = '127.0.0.1' 19 | export const DEFAULT_SERVER_PORT = 8888 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | 16 | strategy: 17 | matrix: 18 | node-version: [16.x] 19 | # os: [ubuntu-latest, windows-latest, macos-latest] 20 | os: [ubuntu-latest] 21 | fail-fast: false 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | 26 | - name: Install pnpm 27 | uses: pnpm/action-setup@v2.2.1 28 | 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v2 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | registry-url: https://registry.npmjs.org/ 34 | cache: "pnpm" 35 | 36 | - run: pnpm install 37 | 38 | - name: Build 39 | run: pnpm run build 40 | 41 | - name: Test 42 | run: pnpm run test 43 | -------------------------------------------------------------------------------- /example/icejs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "buildOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "outDir": "build", 7 | "module": "esnext", 8 | "target": "es6", 9 | "jsx": "react-jsx", 10 | "moduleResolution": "node", 11 | "allowSyntheticDefaultImports": true, 12 | "lib": ["es6", "dom"], 13 | "sourceMap": true, 14 | "allowJs": true, 15 | "rootDir": "./", 16 | "forceConsistentCasingInFileNames": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noImplicitAny": false, 20 | "importHelpers": true, 21 | "strictNullChecks": true, 22 | "suppressImplicitAnyIndexErrors": true, 23 | "noUnusedLocals": true, 24 | "skipLibCheck": true, 25 | "types": ["node"], 26 | "paths": { 27 | "@/*": ["./src/*"], 28 | "ice": [".ice/index.ts"] 29 | } 30 | }, 31 | "include": ["src", ".ice"], 32 | "exclude": ["node_modules", "build", "public"] 33 | } -------------------------------------------------------------------------------- /example/nuxt/pages/index.vue: -------------------------------------------------------------------------------- 1 | 42 | -------------------------------------------------------------------------------- /example/icejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@alifd/scaffold-simple", 3 | "version": "0.1.0", 4 | "description": "使用 TypeScript,未使用任何 UI 库。", 5 | "dependencies": { 6 | "react": "^17.0.2", 7 | "react-dom": "^17.0.2" 8 | }, 9 | "devDependencies": { 10 | "@iceworks/spec": "^1.0.0", 11 | "@types/react": "^17.0.2", 12 | "@types/react-dom": "^17.0.2", 13 | "eslint": "^7.30.0", 14 | "ice.js": "^2.0.0", 15 | "stylelint": "^13.7.2", 16 | "windicss-webpack-plugin": "file:../../" 17 | }, 18 | "scripts": { 19 | "start": "icejs start", 20 | "build": "icejs build", 21 | "lint": "npm run eslint && npm run stylelint", 22 | "eslint": "eslint --cache --ext .js,.jsx,.ts,.tsx ./", 23 | "eslint:fix": "npm run eslint -- --fix", 24 | "stylelint": "stylelint \"**/*.{css,scss,less}\"" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/ice-lab/react-materials/tree/master/scaffolds/simple" 29 | }, 30 | "private": true, 31 | "originTemplate": "@alifd/scaffold-simple" 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: Install pnpm 17 | uses: pnpm/action-setup@v2.2.1 18 | 19 | - name: Use Node.js v16 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: v16 23 | registry-url: https://registry.npmjs.org/ 24 | cache: "pnpm" 25 | 26 | - run: npx conventional-github-releaser -p angular 27 | continue-on-error: true 28 | env: 29 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}} 30 | 31 | - name: Install Dependencies 32 | run: pnpm install 33 | 34 | - name: PNPM build 35 | run: pnpm run build 36 | 37 | - name: Publish to NPM 38 | run: pnpm -r publish --access public --no-git-checks 39 | env: 40 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 41 | -------------------------------------------------------------------------------- /example/nuxt/components/Animation.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | -------------------------------------------------------------------------------- /example/craco/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@craco/craco": "^6.2.0", 7 | "@testing-library/jest-dom": "^5.11.4", 8 | "@testing-library/react": "^11.1.0", 9 | "@testing-library/user-event": "^12.1.10", 10 | "babel-loader": "8.1.0", 11 | "react": "^17.0.2", 12 | "react-dom": "^17.0.2", 13 | "react-scripts": "^4.0.3", 14 | "web-vitals": "^1.0.1", 15 | "windicss-webpack-plugin": "file:../../" 16 | }, 17 | "scripts": { 18 | "start": "craco start", 19 | "build": "craco build", 20 | "test": "craco test", 21 | "eject": "craco eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/excluded-transform.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { getModuleSource, vueWebpackCompiler } from './helpers' 3 | 4 | describe("Excluded transform", function() { 5 | 6 | it('should render vue', done => { 7 | const compiler = vueWebpackCompiler('excluded-transform', { 8 | scan: { 9 | extraTransformTargets: { 10 | detect: [], 11 | css: [ 12 | (resource) => { 13 | return resource.indexOf('should-transform.css') >= 0 14 | } 15 | 16 | ] 17 | } 18 | } 19 | }) 20 | compiler.run((err, stats) => { 21 | expect(stats.compilation.errors).toStrictEqual([]) 22 | 23 | const toNotTransformCss = getModuleSource('should-not-transform', stats) 24 | expect(toNotTransformCss).toContain('theme(') 25 | 26 | // check the windi file has generated the right classes 27 | const toTransformCss = getModuleSource('should-transform', stats) 28 | expect(toTransformCss).not.toContain('theme(') 29 | 30 | done(err) 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /example/next/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/umijs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev", 5 | "build": "umi build", 6 | "postinstall": "umi generate tmp", 7 | "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'", 8 | "test": "umi-test", 9 | "test:coverage": "umi-test --coverage" 10 | }, 11 | "gitHooks": { 12 | "pre-commit": "lint-staged" 13 | }, 14 | "lint-staged": { 15 | "*.{js,jsx,less,md,json}": [ 16 | "prettier --write" 17 | ], 18 | "*.ts?(x)": [ 19 | "prettier --parser=typescript --write" 20 | ] 21 | }, 22 | "dependencies": { 23 | "@ant-design/pro-layout": "^6.5.0", 24 | "@umijs/preset-react": "^1.8.6", 25 | "umi": "^3.4.14" 26 | }, 27 | "devDependencies": { 28 | "@types/react": "^17.0.0", 29 | "@types/react-dom": "^17.0.0", 30 | "@umijs/test": "^3.4.14", 31 | "windicss-webpack-plugin": "file:../../", 32 | "lint-staged": "^10.0.7", 33 | "prettier": "^2.2.0", 34 | "react": "17.x", 35 | "react-dom": "17.x", 36 | "typescript": "^4.1.2", 37 | "yorkie": "^2.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/icejs/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Simple 3 | 4 | > A TypeScript simple template 5 | 6 | ## 使用 7 | 8 | ```bash 9 | # 安装依赖 10 | $ npm install 11 | 12 | # 启动服务 13 | $ npm start # visit http://localhost:3333 14 | ``` 15 | 16 | [More docs](https://ice.work/docs/guide/about). 17 | 18 | ## 目录 19 | 20 | ```md 21 | ├── build/ # 构建产物 22 | ├── mock/ # 本地模拟数据 23 | │ ├── index.[j,t]s 24 | ├── public/ 25 | │ ├── index.html # 应用入口 HTML 26 | │ └── favicon.png # Favicon 27 | ├── src/ # 源码路径 28 | │ ├── components/ # 自定义业务组件 29 | │ │ └── Guide/ 30 | │ │ ├── index.[j,t]sx 31 | │ │ └── index.module.scss 32 | │ ├── pages/ # 页面 33 | │ │ └── index.tsx/ 34 | │ ├── global.scss # 全局样式 35 | │ └── app.[j,t]s[x] # 应用入口脚本 36 | ├── README.md 37 | ├── package.json 38 | ├── .editorconfig 39 | ├── .eslintignore 40 | ├── .eslintrc.[j,t]s 41 | ├── .gitignore 42 | ├── .stylelintignore 43 | ├── .stylelintrc.[j,t]s 44 | ├── .gitignore 45 | └── [j,t]sconfig.json 46 | ``` 47 | -------------------------------------------------------------------------------- /test/helpers/reactWebpackCompiler.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import webpack from 'webpack' 3 | import WebpackWindiCSSPlugin from '../../dist/plugin.mjs' 4 | 5 | export function reactWebpackCompiler (type = 'react', config = {}) { 6 | const root = path.dirname(__dirname) 7 | const context = path.join(root, 'fixtures', type) 8 | return webpack({ 9 | entry: `./index.js`, 10 | context, 11 | mode: 'development', 12 | devtool: false, 13 | output: { 14 | path: path.join(root, '/dist'), 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.css$/, 20 | use: [ 21 | 'css-loader' 22 | ] 23 | }, 24 | { 25 | test: /\.jsx?$/, 26 | exclude: /node_modules/, 27 | use: { 28 | loader: 'babel-loader', 29 | options: { 30 | presets: [ 31 | ['@babel/preset-react'] 32 | ] 33 | } 34 | } 35 | }, 36 | ] 37 | }, 38 | plugins: [ 39 | new WebpackWindiCSSPlugin({ 40 | root: context, 41 | ...config, 42 | }), 43 | ], 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /example/vue-cli-next/src/App.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 46 | -------------------------------------------------------------------------------- /example/vue-cli-next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^2.6.11" 13 | }, 14 | "devDependencies": { 15 | "@vue/cli-plugin-babel": "5.0.0-alpha.8", 16 | "@vue/cli-service": "5.0.0-alpha.8", 17 | "babel-eslint": "^10.1.0", 18 | "eslint-plugin-vue": "^6.2.2", 19 | "less": "^4.1.1", 20 | "less-loader": "^8.1.1", 21 | "sass": "^1.32.12", 22 | "sass-loader": "^11.0.1", 23 | "stylus": "^0.54.8", 24 | "stylus-loader": "^5.0.0", 25 | "vue-template-compiler": "^2.6.11", 26 | "windicss-webpack-plugin": "file:../../" 27 | }, 28 | "eslintConfig": { 29 | "root": true, 30 | "env": { 31 | "node": true 32 | }, 33 | "extends": [ 34 | "plugin:vue/essential", 35 | "eslint:recommended" 36 | ], 37 | "parserOptions": { 38 | "parser": "babel-eslint" 39 | }, 40 | "rules": {} 41 | }, 42 | "browserslist": [ 43 | "> 1%", 44 | "last 2 versions", 45 | "not dead" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Button.stories.js: -------------------------------------------------------------------------------- 1 | import MyButton from './Button.vue'; 2 | 3 | export default { 4 | title: 'Example/Button', 5 | component: MyButton, 6 | argTypes: { 7 | backgroundColor: { control: 'color' }, 8 | size: { control: { type: 'select', options: ['small', 'medium', 'large'] } }, 9 | onClick: {}, 10 | }, 11 | }; 12 | 13 | const Template = (args) => ({ 14 | // Components used in your story `template` are defined in the `components` object 15 | components: { MyButton }, 16 | // The story's `args` need to be mapped into the template through the `setup()` method 17 | setup() { 18 | return { args }; 19 | }, 20 | // And then the `args` are bound to your component with `v-bind="args"` 21 | template: '', 22 | }); 23 | 24 | export const Primary = Template.bind({}); 25 | Primary.args = { 26 | primary: true, 27 | label: 'Button', 28 | }; 29 | 30 | export const Secondary = Template.bind({}); 31 | Secondary.args = { 32 | label: 'Button', 33 | }; 34 | 35 | export const Large = Template.bind({}); 36 | Large.args = { 37 | size: 'large', 38 | label: 'Button', 39 | }; 40 | 41 | export const Small = Template.bind({}); 42 | Small.args = { 43 | size: 'small', 44 | label: 'Button', 45 | }; 46 | -------------------------------------------------------------------------------- /example/vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0" 13 | }, 14 | "devDependencies": { 15 | "@vue/cli-plugin-babel": "~4.5.0", 16 | "@vue/cli-plugin-eslint": "~4.5.0", 17 | "@vue/cli-service": "~4.5.0", 18 | "@vue/compiler-sfc": "^3.0.0", 19 | "babel-eslint": "^10.1.0", 20 | "eslint": "^6.7.2", 21 | "eslint-plugin-vue": "^7.0.0-0", 22 | "less": "^4.1.1", 23 | "less-loader": "^7", 24 | "sass": "^1.32.12", 25 | "sass-loader": "^10", 26 | "stylus": "^0.54.8", 27 | "stylus-loader": "^3", 28 | "windicss-webpack-plugin": "file:../../" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/vue3-essential", 37 | "eslint:recommended" 38 | ], 39 | "parserOptions": { 40 | "parser": "babel-eslint" 41 | }, 42 | "rules": {} 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions", 47 | "not dead" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /test/fixtures/vue-layers/templates/App.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /test/fixtures/excluded-transform/templates/App.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /test/fixtures/vue-directives/templates/App.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Button.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 53 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/page.css: -------------------------------------------------------------------------------- 1 | section { 2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | font-size: 14px; 4 | line-height: 24px; 5 | padding: 48px 20px; 6 | margin: 0 auto; 7 | max-width: 600px; 8 | color: #333; 9 | } 10 | 11 | h2 { 12 | font-weight: 900; 13 | font-size: 32px; 14 | line-height: 1; 15 | margin: 0 0 4px; 16 | display: inline-block; 17 | vertical-align: top; 18 | } 19 | 20 | p { 21 | margin: 1em 0; 22 | } 23 | 24 | a { 25 | text-decoration: none; 26 | color: #1ea7fd; 27 | } 28 | 29 | ul { 30 | padding-left: 30px; 31 | margin: 1em 0; 32 | } 33 | 34 | li { 35 | margin-bottom: 8px; 36 | } 37 | 38 | .tip { 39 | display: inline-block; 40 | border-radius: 1em; 41 | font-size: 11px; 42 | line-height: 12px; 43 | font-weight: 700; 44 | background: #e7fdd8; 45 | color: #66bf3c; 46 | padding: 4px 12px; 47 | margin-right: 10px; 48 | vertical-align: top; 49 | } 50 | 51 | .tip-wrapper { 52 | font-size: 13px; 53 | line-height: 20px; 54 | margin-top: 40px; 55 | margin-bottom: 40px; 56 | } 57 | 58 | .tip-wrapper svg { 59 | display: inline-block; 60 | height: 12px; 61 | width: 12px; 62 | margin-right: 4px; 63 | vertical-align: top; 64 | margin-top: 3px; 65 | } 66 | 67 | .tip-wrapper svg path { 68 | fill: #1ea7fd; 69 | } 70 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /example/vue2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\"" 10 | }, 11 | "dependencies": { 12 | "core-js": "^3.19.3", 13 | "video.js": "^7.17.0", 14 | "vue": "^2.6.14", 15 | "vue-i18n": "^8.26.3" 16 | }, 17 | "devDependencies": { 18 | "@intlify/vue-i18n-loader": "^4.0.1", 19 | "@vue/cli-plugin-babel": "~4.5.15", 20 | "@vue/cli-plugin-eslint": "~4.5.15", 21 | "@vue/cli-service": "~4.5.15", 22 | "babel-eslint": "^10.1.0", 23 | "eslint": "^6.7.2", 24 | "eslint-plugin-vue": "^6.2.2", 25 | "less": "^4.1.2", 26 | "less-loader": "^7.3.0", 27 | "sass": "^1.32.12", 28 | "sass-loader": "^10", 29 | "stylus": "^0.54.8", 30 | "stylus-loader": "^3", 31 | "vue-cli-plugin-i18n": "~2.3.1" 32 | }, 33 | "eslintConfig": { 34 | "root": true, 35 | "env": { 36 | "node": true 37 | }, 38 | "extends": [ 39 | "plugin:vue/essential", 40 | "eslint:recommended" 41 | ], 42 | "parserOptions": { 43 | "parser": "babel-eslint" 44 | }, 45 | "rules": {} 46 | }, 47 | "browserslist": [ 48 | "> 1%", 49 | "last 2 versions", 50 | "not dead" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /test/fixtures/vue/templates/App.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 | 52 | { 53 | "en": { 54 | "hello": "hello world!" 55 | }, 56 | "ja": { 57 | "hello": "こんにちは、世界!" 58 | } 59 | } 60 | 61 | 62 | 67 | -------------------------------------------------------------------------------- /example/icejs/src/pages/Home/index.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => { 2 | return ( 3 |
4 |

Welcome to icejs!

5 |

6 | This is an awesome project powered by  7 | 8 | WindiCSS 9 | 10 | , enjoy it! 11 |

12 | 27 |
28 |
{ 31 | location.href = 'https://ice.work/docs/guide/about'; 32 | }} 33 | > 34 | Get Started with icejs 35 |
36 |
{ 39 | location.href = 'https://windicss.org'; 40 | }} 41 | > 42 | Get Started with WindiCSS 43 |
44 |
45 |
46 | ); 47 | }; 48 | 49 | export default Home; 50 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /example/vue2/src/App.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "en": { 4 | "hello": "hello world!" 5 | }, 6 | "ja": { 7 | "hello": "JAPAN こんにちは、世界!" 8 | } 9 | } 10 | 11 | 12 | 35 | 36 | 64 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Header.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 50 | -------------------------------------------------------------------------------- /example/vue3-storybook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "storybook": "start-storybook -p 6006", 10 | "build-storybook": "build-storybook" 11 | }, 12 | "dependencies": { 13 | "core-js": "^3.6.5", 14 | "vue": "^3.0.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.14.6", 18 | "@storybook/addon-actions": "^6.3.0", 19 | "@storybook/addon-essentials": "^6.3.0", 20 | "@storybook/addon-links": "^6.3.0", 21 | "@storybook/vue3": "^6.3.0", 22 | "@vue/cli-plugin-babel": "~4.5.0", 23 | "@vue/cli-plugin-eslint": "~4.5.0", 24 | "@vue/cli-service": "~4.5.0", 25 | "@vue/compiler-sfc": "^3.0.0", 26 | "babel-eslint": "^10.1.0", 27 | "babel-loader": "^8.2.2", 28 | "eslint": "^6.7.2", 29 | "eslint-plugin-vue": "^7.0.0-0", 30 | "less": "^4.1.1", 31 | "less-loader": "^7", 32 | "sass": "^1.32.12", 33 | "sass-loader": "^10", 34 | "stylus": "^0.54.8", 35 | "stylus-loader": "^3", 36 | "vue-loader": "^16.2.0" 37 | }, 38 | "eslintConfig": { 39 | "root": true, 40 | "env": { 41 | "node": true 42 | }, 43 | "extends": [ 44 | "plugin:vue/vue3-essential", 45 | "eslint:recommended" 46 | ], 47 | "parserOptions": { 48 | "parser": "babel-eslint" 49 | }, 50 | "rules": {} 51 | }, 52 | "browserslist": [ 53 | "> 1%", 54 | "last 2 versions", 55 | "not dead" 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /example/vue3-storybook/src/App.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 57 | 58 | 69 | -------------------------------------------------------------------------------- /example/vue3/src/App.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 57 | 58 | 69 | -------------------------------------------------------------------------------- /example/next/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /src/loaders/dev-tools.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'node:fs' 2 | import { resolve } from 'pathe' 3 | import type { Compiler, loader } from 'webpack' 4 | import { isDev, isWebCompilerTarget } from '../core/utils' 5 | import { DEVTOOLS_POST_PATH } from '../core/constants' 6 | 7 | const DEVTOOLS_CLIENT_PATH = resolve(__dirname, '../runtime/client.cjs') 8 | 9 | function getMockClassesInjector(compiler: Compiler) { 10 | const completions = compiler.$windi.getCompletions() 11 | const comment = '/* Windi CSS mock class names for devtools auto-completion */\n' 12 | const css = [ 13 | ...completions.color, 14 | ...completions.static, 15 | ].map((name: string) => `.${compiler.$windi.processor.e(name)}{}`).join('') 16 | return ` 17 | const style = document.createElement('style') 18 | style.setAttribute('type', 'text/css') 19 | style.innerHTML = ${JSON.stringify(comment + css)} 20 | document.head.prepend(style) 21 | ` 22 | } 23 | async function devtoolsLoader(this: loader.LoaderContext, source: string): Promise { 24 | const callback = this.async()! 25 | 26 | if (!this._compiler) { 27 | callback(null, source) 28 | return 29 | } 30 | 31 | this.cacheable(true) 32 | 33 | const { port, host } = await this._compiler.$windi.server.ensureStart() 34 | 35 | if (isWebCompilerTarget(this._compiler.options.target) && isDev()) { 36 | const clientContent = readFileSync(DEVTOOLS_CLIENT_PATH, 'utf-8') 37 | .replace('__POST_PATH__', `http://${host}:${port}${DEVTOOLS_POST_PATH}`) 38 | 39 | const mockClasses = getMockClassesInjector(this._compiler) 40 | 41 | callback(null, `${clientContent}\n${mockClasses}`) 42 | } 43 | else { 44 | // returns the empty string if it is not in dev environment or if the compile target is not web, e.g. SSR. 45 | callback(null, '') 46 | } 47 | } 48 | 49 | export default devtoolsLoader 50 | -------------------------------------------------------------------------------- /example/craco/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { UserOptions, WindiPluginUtils } from '@windicss/plugin-utils' 2 | import type Server from './core/server' 3 | 4 | // virtual module prefix 5 | // @ts-expect-error virtual module 6 | declare module 'virtual:windi.css' {} 7 | // @ts-expect-error virtual module 8 | declare module 'virtual:windi-base.css' {} 9 | // @ts-expect-error virtual module 10 | declare module 'virtual:windi-components.css' {} 11 | // @ts-expect-error virtual module 12 | declare module 'virtual:windi-utilities.css' {} 13 | 14 | // no prefix 15 | // @ts-expect-error virtual module 16 | declare module 'windi.css' {} 17 | // @ts-expect-error virtual module 18 | declare module 'windi-base.css' {} 19 | // @ts-expect-error virtual module 20 | declare module 'windi-components.css' {} 21 | // @ts-expect-error virtual module 22 | declare module 'windi-utilities.css' {} 23 | 24 | declare module 'webpack' { 25 | interface Compiler { 26 | $windi: WindiPluginUtils & { 27 | dirty: Set 28 | root: string 29 | virtualModules: Map 30 | initException?: Error 31 | invalidateCssModules: (resource: string, modules: string[]) => void 32 | server: Server 33 | } 34 | } 35 | } 36 | 37 | export type WindiCSSWebpackPluginOptions = UserOptions & { 38 | /** 39 | * Reuse existing utils if exists 40 | */ 41 | utils?: WindiPluginUtils 42 | /** 43 | * The path where the virtual module should be injected. By default this is the project root but for 44 | * some projects (such as craco), specifying the directory is needed. 45 | * 46 | * @default '' 47 | */ 48 | virtualModulePath: string 49 | /** 50 | * Options for devtools backend server. 51 | */ 52 | server?: { 53 | /** 54 | * Port for devtools backend server. 55 | * 56 | * @default 8888 57 | */ 58 | port?: number 59 | /** 60 | * Host for devtools backend server. 61 | * 62 | * @default '127.0.0.1' 63 | */ 64 | host?: string 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/layers.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { getModuleSource, vueWebpackCompiler, reactWebpackCompiler } from './helpers' 3 | 4 | describe("Layers test", function() { 5 | 6 | it('should render vue', done => { 7 | const compiler = vueWebpackCompiler('vue-layers') 8 | compiler.run((err, stats) => { 9 | expect(stats.compilation.errors).toStrictEqual([]) 10 | // check the windi file has generated the right classes 11 | const windiBase = getModuleSource('virtual:windi-base.css', stats) 12 | expect(windiBase).toContain('body {') 13 | expect(windiBase).toMatchSnapshot('windi base') 14 | 15 | const windiComponents = getModuleSource('virtual:windi-components.css', stats) 16 | expect(windiComponents).toContain('windicss layer components') 17 | expect(windiComponents).toMatchSnapshot('windi components') 18 | 19 | const windiUtils = getModuleSource('virtual:windi-utilities.css', stats) 20 | expect(windiUtils).toContain('bg-teal-900:hover') 21 | expect(windiUtils).toMatchSnapshot('windi utilities') 22 | 23 | done(err) 24 | }); 25 | }); 26 | it('should render react', done => { 27 | const compiler = reactWebpackCompiler('react-layers') 28 | compiler.run((err, stats) => { 29 | expect(stats.compilation.errors).toStrictEqual([]) 30 | // check the windi file has generated the right classes 31 | const windiBase = getModuleSource('virtual:windi-base.css', stats) 32 | expect(windiBase).toContain('body {') 33 | expect(windiBase).toMatchSnapshot('windi base') 34 | 35 | const windiComponents = getModuleSource('virtual:windi-components.css', stats) 36 | expect(windiComponents).toContain('windicss layer components') 37 | expect(windiComponents).toMatchSnapshot('windi components') 38 | 39 | const windiUtils = getModuleSource('virtual:windi-utilities.css', stats) 40 | expect(windiUtils).toContain('bg-blue-500:hover') 41 | expect(windiUtils).toMatchSnapshot('windi utilities') 42 | 43 | done(err) 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /test/helpers/vueWebpackCompiler.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import webpack from 'webpack' 3 | import WebpackWindiCSSPlugin from '../../dist/plugin.mjs' 4 | import VueLoaderPlugin from 'vue-loader/lib/plugin' 5 | 6 | export function vueWebpackCompiler (type = 'vue', config = {}) { 7 | const root = path.dirname(__dirname) 8 | const context = path.join(root, 'fixtures', type) 9 | return webpack({ 10 | entry: `./index.js`, 11 | context, 12 | mode: 'development', 13 | devtool: false, 14 | output: { 15 | path: path.join(root, '/dist'), 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | resourceQuery: /blockType=i18n/, 21 | type: 'javascript/auto', 22 | loader: '@intlify/vue-i18n-loader', 23 | }, 24 | { 25 | test: /\.css$/, 26 | use: [ 27 | 'vue-style-loader', 28 | 'css-loader' 29 | ] 30 | }, 31 | { 32 | test: /\.vue$/, 33 | loader: 'vue-loader' 34 | }, 35 | { 36 | test: /\.scss$/, 37 | use: [ 38 | 'vue-style-loader', 39 | 'css-loader', 40 | 'sass-loader' 41 | ] 42 | }, 43 | { 44 | test: /\.sass$/, 45 | use: [ 46 | 'vue-style-loader', 47 | 'css-loader', 48 | { 49 | loader: 'sass-loader', 50 | options: { 51 | sassOptions: { 52 | indentedSyntax: true 53 | } 54 | } 55 | } 56 | ] 57 | }, 58 | { 59 | test: /\.less$/, 60 | use: [ 61 | 'vue-style-loader', 62 | 'css-loader', 63 | 'less-loader' 64 | ] 65 | }, 66 | { 67 | test: /\.styl(us)?$/, 68 | use: [ 69 | 'vue-style-loader', 70 | 'css-loader', 71 | 'stylus-loader' 72 | ] 73 | }, 74 | ] 75 | }, 76 | plugins: [ 77 | new WebpackWindiCSSPlugin({ 78 | root: context, 79 | ...config, 80 | }), 81 | new VueLoaderPlugin() 82 | ], 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /example/nuxt/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /example/vue3/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /test/regex.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | 3 | describe("Virtual module regex tests", function() { 4 | 5 | it('should match on windows path', () => { 6 | expect( 7 | /virtual:windi-?(.*?)\.css/.test('D:\\a\\windicss-webpack-plugin\\windicss-webpack-plugin\\test\\virtual:windi.css') 8 | ).toBeTruthy() 9 | }); 10 | }); 11 | 12 | describe("CSS parsing skip", function() { 13 | 14 | it('should detect when to skip css parsing', () => { 15 | expect(/@(apply|variants|screen|layer)\s/gm.test('import \'virtual:windi.css\';\n' + 16 | ' export default function Layout({\n' + 17 | ' title,\n' + 18 | ' children\n' + 19 | ' }) {\n' + 20 | ' return /*#__PURE__*/React.createElement(\\"div\\", {\n' + 21 | ' id: \\"layout-wrapper\\",\n' + 22 | ' className: \'bg-gray-100 text-gray-900 dark:bg-gray-900 dark:text-gray-100\'\n' + 23 | ' }, /*#__PURE__*/React.createElement(Head, null, /*#__PURE__*/React.createElement(\\"title\\", null, title)), children, /*#__PURE__*/React.createElement(\\"style\\", {\n' + 24 | ' jsx: true,\n' + 25 | ' global: true\n' + 26 | ' }, `\n' + 27 | ' body {\n' + 28 | ' @apply m-0 p-0 w-100vw h-100vh overflow-hidden hover:bg-blue-500 hover:text-xs;\n' + 29 | ' font-family: \'-apple-system\', \'BlinkMacSystemFont\', \'Segoe UI\',\n' + 30 | ' \'Roboto\', \'Oxygen\', \'Ubuntu\', \'Cantarell\', \'Fira Sans\', \'Droid Sans\',\n' + 31 | ' \'Helvetica Neue\', \'sans-serif\';\n' + 32 | ' -webkit-font-smoothing: antialiased;\n' + 33 | ' -moz-osx-font-smoothing: grayscale;\n' + 34 | ' }\n' + 35 | ' `));\n' + 36 | ' }')).toBeTruthy() 37 | }); 38 | it('sass-global', () => { 39 | expect(/@(apply|variants|screen|layer)\s/gm.test('.sass-global\n' + 40 | '@apply bg-orange-400 text-white p-4 w-1/4 transition hover:(bg-orange-900 text-orange-100)\n' + 41 | ' h2\n' + 42 | '@apply font-bold text-sm')).toBeTruthy() 43 | expect(/@(apply|variants|screen|layer)\s/gm.test('.sass-global\n' + 44 | '@apply bg-orange-400 text-white p-4 w-1/4 transition hover:(bg-orange-900 text-orange-100)\n' + 45 | ' h2\n' + 46 | '@apply font-bold text-sm')).toBeTruthy() 47 | }); 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /src/core/utils.ts: -------------------------------------------------------------------------------- 1 | import type { WindiPluginUtils } from '@windicss/plugin-utils' 2 | import type webpack from 'webpack' 3 | import { HAS_DIRECTIVE_TEST, HAS_THEME_FUNCTION_TEST, MODULE_ID_VIRTUAL_PREFIX } from './constants' 4 | import debug from './debug' 5 | 6 | export function cssRequiresTransform(source: string) { 7 | return HAS_DIRECTIVE_TEST.test(source) || HAS_THEME_FUNCTION_TEST.test(source) 8 | } 9 | 10 | export function isJsx(source: string) { 11 | return /{`(.*)`}/gms.test(source) 12 | } 13 | 14 | export function transformCSS(service: WindiPluginUtils, source: string, resource: string) { 15 | if (!source || source.length <= 0) 16 | return source 17 | 18 | // make sure the transform is required, can be expensive 19 | if (!cssRequiresTransform(source)) 20 | return source 21 | 22 | let output = source 23 | try { 24 | output = service.transformCSS(source, resource, { globaliseKeyframes: true }) 25 | if (!output || output.length <= 0) { 26 | debug.loader(`[WindiCSS] Invalid response from windi core transforming resource: ${resource}.`) 27 | return source 28 | } 29 | debug.loader('Transformed CSS', resource) 30 | } 31 | catch (e) { 32 | debug.loader(`[WindiCSS] Exception when transforming CSS for resource: ${resource}.`, e) 33 | return source 34 | } 35 | return output 36 | } 37 | 38 | /** 39 | * Default function. Take the value or the default 40 | */ 41 | export function def(val: any, def: any) { 42 | if (val) 43 | return val 44 | 45 | return def 46 | } 47 | 48 | export function getChangedModuleNames(utils: WindiPluginUtils) { 49 | if (utils.hasPending) 50 | utils.buildPendingStyles() 51 | 52 | const moduleNames = [ 53 | `${MODULE_ID_VIRTUAL_PREFIX}.css`, 54 | ] 55 | 56 | Object.entries(utils.layersMeta).forEach(([name, meta]) => { 57 | if (meta.cssCache == null) 58 | moduleNames.push(`${MODULE_ID_VIRTUAL_PREFIX}-${name}.css`) 59 | }) 60 | 61 | return moduleNames 62 | } 63 | 64 | export const isDev = () => process.env.NODE_ENV === 'development' 65 | 66 | export function isWebCompilerTarget(target: webpack.Configuration['target']) { 67 | let isWeb = true 68 | if (typeof target === 'string') { 69 | isWeb = !target.includes('node') 70 | } 71 | else if (Array.isArray(target)) { 72 | target.forEach((str) => { 73 | if (str.includes('node')) 74 | isWeb = false 75 | }) 76 | } 77 | else { 78 | isWeb = false 79 | } 80 | return isWeb 81 | } 82 | -------------------------------------------------------------------------------- /example/next/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | padding: 0 0.5rem; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | 10 | .main { 11 | padding: 5rem 0; 12 | flex: 1; 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: center; 16 | align-items: center; 17 | } 18 | 19 | .footer { 20 | width: 100%; 21 | height: 100px; 22 | border-top: 1px solid #eaeaea; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .footer img { 29 | margin-left: 0.5rem; 30 | } 31 | 32 | .footer a { 33 | display: flex; 34 | justify-content: center; 35 | align-items: center; 36 | } 37 | 38 | .title a { 39 | color: #0070f3; 40 | text-decoration: none; 41 | } 42 | 43 | .title a:hover, 44 | .title a:focus, 45 | .title a:active { 46 | text-decoration: underline; 47 | } 48 | 49 | .title { 50 | margin: 0; 51 | line-height: 1.15; 52 | font-size: 4rem; 53 | } 54 | 55 | .title, 56 | .description { 57 | text-align: center; 58 | } 59 | 60 | .description { 61 | line-height: 1.5; 62 | font-size: 1.5rem; 63 | } 64 | 65 | .code { 66 | background: #fafafa; 67 | border-radius: 5px; 68 | padding: 0.75rem; 69 | font-size: 1.1rem; 70 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 71 | Bitstream Vera Sans Mono, Courier New, monospace; 72 | } 73 | 74 | .grid { 75 | display: flex; 76 | align-items: center; 77 | justify-content: center; 78 | flex-wrap: wrap; 79 | max-width: 800px; 80 | margin-top: 3rem; 81 | } 82 | 83 | .card { 84 | margin: 1rem; 85 | flex-basis: 45%; 86 | padding: 1.5rem; 87 | text-align: left; 88 | color: inherit; 89 | text-decoration: none; 90 | border: 1px solid #eaeaea; 91 | border-radius: 10px; 92 | transition: color 0.15s ease, border-color 0.15s ease; 93 | } 94 | 95 | .card:hover, 96 | .card:focus, 97 | .card:active { 98 | color: #0070f3; 99 | border-color: #0070f3; 100 | } 101 | 102 | .card h3 { 103 | margin: 0 0 1rem 0; 104 | font-size: 1.5rem; 105 | } 106 | 107 | .card p { 108 | margin: 0; 109 | font-size: 1.25rem; 110 | line-height: 1.5; 111 | } 112 | 113 | .logo { 114 | height: 1em; 115 | } 116 | 117 | @media (max-width: 600px) { 118 | .grid { 119 | width: 100%; 120 | flex-direction: column; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/loaders/windicss-style-pitcher.ts: -------------------------------------------------------------------------------- 1 | import type { loader } from 'webpack' 2 | 3 | type LoaderTest = (l: { path: string; ident?: string }) => boolean 4 | 5 | const windiTemplateTest: LoaderTest = l => /(\/|\\|@)windicss-template/.test(l.path) 6 | const windiStylePitcherTest: LoaderTest = l => /(\/|\\|@)windicss-style-pitcher/.test(l.path) 7 | const postCssLoaderTest: LoaderTest = l => /(\/|\\|@)postcss-loader/.test(l.path) 8 | const cssLoaderTest: LoaderTest = l => /(\/|\\|@)css-loader/.test(l.path) 9 | 10 | /* 11 | * Move the position of the transform-template loader for Vue SFCs. 12 | * 13 | * We move it just after the PostCSS loader 14 | */ 15 | export const pitch = function (this: loader.LoaderContext, remainingRequest: string) { 16 | const findLoaderIndex = (test: LoaderTest) => this.loaders.findIndex((loader) => { 17 | return test(loader) && !loader.normalExecuted 18 | }) 19 | 20 | const markLoaderAsExecuted: (test: LoaderTest) => any = (test) => { 21 | let index, loader 22 | while ((index = findLoaderIndex(test)) !== -1) { 23 | loader = this.loaders[index] 24 | /* 25 | * Hacky solution to avoid the loader from running. 26 | * Previously we removed the loader entirely however, this caused 27 | * a conflict with other loaders (see https://github.com/windicss/windicss-webpack-plugin/issues/111). 28 | */ 29 | loader.pitchExecuted = true 30 | loader.normalExecuted = true 31 | } 32 | return loader 33 | } 34 | 35 | // remove the pitcher immediately 36 | markLoaderAsExecuted(windiStylePitcherTest) 37 | 38 | // make sure we're dealing with style-loader 39 | if (!remainingRequest.includes('&type=style')) { 40 | // clean up 41 | markLoaderAsExecuted(windiTemplateTest) 42 | return 43 | } 44 | 45 | let newTemplateLoaderIndex = findLoaderIndex(postCssLoaderTest) 46 | // just in-case they don't have post-css for whatever reason we also search for the css-loader 47 | if (newTemplateLoaderIndex === -1) 48 | newTemplateLoaderIndex = findLoaderIndex(cssLoaderTest) 49 | 50 | // we couldn't find either PostCSS loader or CSS loader so we bail out 51 | if (newTemplateLoaderIndex === -1) { 52 | // clean up 53 | markLoaderAsExecuted(windiTemplateTest) 54 | return 55 | } 56 | 57 | const templateLoader = markLoaderAsExecuted(windiTemplateTest) 58 | // re-insert the template-loader in the right spot 59 | if (templateLoader) 60 | this.loaders.splice(newTemplateLoaderIndex + 1, 0, templateLoader) 61 | } 62 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /example/craco/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/icejs/public/favicon.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | IHDR����g- 4 | fIDATx��klSe�_E��Cza�ʸ ��0�2@�>x ^?(bl;ƌZ���& &��/^h)0. 5 | ��4E�@� �Զnc�v�<>o��ҵ��zN����� �lky��{zΙ�hLv�-vM���q����q��M��c#?����鲺���8�� ���������=��o⏽�/X*i����hX�4���67�͢�N��$�*�}������#�)k90N/ �)O����&[��?�g���]9�M�**�v�����d���?�a����t.%��0�*�6�����A�r� �����S$����kO�-<�zT�����Y��/�$�>X��`��2�M��_���߹Zn�� r 6 | ���\�8d��g7�*i����K����&���g���D`l�����Cf.�1���@-��N���������M��+Ĺ�Fʷ���$,,]Zl.�W� 7��i�\�6!'y�-@��>��7�\������u��4L5XW�]����^��w�~�<��_C��3C�iMf�+����֒���0�1�4J�����0�9-@���/R\��{xfm�"���W�,2gF+ +��jK&�M��y^S�Y*�*@��F�z�%���@@E9����44.GJ6�9Ԥ�K@���4�T�;�� �8O��=ovC�Rj����x`�CE��y����Ʉ&�i嬓W� 3QZ{n������upy����'�|���Ȓ�M�5� �����o���8g�G�z�����0_z���=���=��Ùu�7�\�y����C�������ܦ؅��F�x*���5��h?�� `�.�[�UT(�B�qZZ�Z�v��A���-G�M��tD.)�?����DD�.�Y�g�N��V�;� M�V�Mɞ�xZI-���~5 7�,��!pe�/�������!�e����(��~.�IfRM'D2�����>���wt�g�vi�i��*l.�-2Ź+4�� �w�C1)ܕ2��"�N�/�}�����H�zǤd�� ����"Y�C��-J�t�����D 7 | �i��s��� �d�ݴ�~ȝ/(��&�ۂ4}�YZЖ��Hvq��6� ^~��T��<P�7HJj���9 %�p/���4A�S�sG�=�IiT���~Xў�����<�P 4�IY��o��0 8 | ���<�*}�S��͎m�je�p'�æ4����"WL��3��᧜��㇭ �����B/�;�r?lR����!���;�Y$� 9 | K�w���C���m�a�^���n�F뇾�k�`����3< �,q�C���q���<?��2_�WS�0:���i�,7C@���C�E�Q/�xR������W�f����嵍+ 10 | � ����yI�L0�J�c��!ݥ�EW���$[�����f)]6�&ݔnR�n 11 | �t��&I����,J�Ē5��a;�%[��N&�4rl����3�����^ )������y������Od?�i����<�v��91��wm�3�D(���{S�������~BFz5�!��Z���:*�j���I�o��_��"��7�W�H~0�@�<3��>��G��_�U���f�C����x�e��/ꇕOe?�:���~�~��督�^σ�&(��A�+�_��٦�1�����j�O�|bf8��8���@��):��r�{O@w�h���f��~PY� ���n��� ���l����+����ּHz�A�����!��f��Xncjd�ؐ! 12 | f�I���=�η�H.S<��\@���t��]lD���U���0�������������2������ �����d�0*V���U�$�p�Β7��D�CW����,nv����В��Y�������oӼ��?�%#��Ӧ�こ�hz�4�FsI�L����d�]��'krP�� ]��SW^��)�m}ѹ������f!kskz��:w8-Q��Q� �$�S[I��:��П~�������~����-��S�S� Q�t��x�$O�%^��&Z�@[j�r ��������!֋����"�Ʋ�I�r�M��m}PM�?�3b��)�r������X��jV��a�V��,�W�][� ^�͝3/ivOG����|G�>���25����xI�n&�o� �T̷����������w�+ ݪ]�X��rz��>�~K-O ��Μ�7dg�}12SX�m��-�t�{Ř[� 13 | l { 7 | const compiler = reactWebpackCompiler() 8 | compiler.run((err, stats) => { 9 | expect(stats.compilation.errors).toStrictEqual([]) 10 | let transformedLayout = getModuleSource('layout.jsx', stats) 11 | expect(transformedLayout).not.toContain('@apply') 12 | expect(transformedLayout).toMatchSnapshot('layout1') 13 | transformedLayout = getModuleSource('layout2.jsx', stats) 14 | expect(transformedLayout).not.toContain('@apply') 15 | expect(transformedLayout).toMatchSnapshot('layout2') 16 | // check the windi file has generated the right classes 17 | const windi = getModuleSource('virtual:windi.css', stats) 18 | expect(windi).toContain('bg-blue-500') 19 | expect(windi).toMatchSnapshot('vue windi') 20 | done(err) 21 | }); 22 | }); 23 | 24 | it('should render vue', done => { 25 | const compiler = vueWebpackCompiler() 26 | compiler.run((err, stats) => { 27 | expect(stats.compilation.errors).toStrictEqual([]) 28 | const transformedLayout = getModuleSource('App.vue?vue&type=template', stats) 29 | expect(transformedLayout).not.toContain('hover:(text-green-100 rounded-full bg-teal-900)') 30 | expect(transformedLayout).toMatchSnapshot('vue template') 31 | // check the windi file has generated the right classes 32 | const windi = getModuleSource('virtual:windi.css', stats) 33 | expect(windi).toContain('text-green-100') 34 | expect(windi).toMatchSnapshot('vue windi') 35 | 36 | const scss = getModuleSource('main.scss', stats) 37 | expect(scss).not.toContain('@apply') 38 | expect(scss).toContain('background-color:') 39 | expect(scss).toMatchSnapshot('vue scss') 40 | 41 | // .sass seems to be broken 42 | // const sass = getModuleSource('main.sass', stats) 43 | // expect(sass).not.toContain('@apply') 44 | // expect(sass).toContain('background-color:') 45 | // expect(sass).toMatchSnapshot('vue sass') 46 | 47 | const less = getModuleSource('main.less', stats) 48 | expect(less).not.toContain('@apply') 49 | expect(less).toContain('background-color:') 50 | expect(less).toMatchSnapshot('vue less') 51 | 52 | const css = getModuleSource('plain.css', stats) 53 | expect(css).not.toContain('@apply') 54 | expect(css).toContain('background-color:') 55 | expect(css).toMatchSnapshot('vue css') 56 | done(err) 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Page.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "windicss-webpack-plugin", 3 | "version": "1.8.0", 4 | "packageManager": "pnpm@8.7.4", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Harlan Wilton", 8 | "email": "harlan@harlanzw.com" 9 | }, 10 | "exports": { 11 | "import": "./dist/plugin.mjs", 12 | "require": "./dist/plugin.cjs", 13 | "types": "./dist/plugin.d.ts" 14 | }, 15 | "main": "./dist/plugin.cjs", 16 | "module": "./dist/plugin.mjs", 17 | "types": "./dist/plugin.d.ts", 18 | "homepage": "https://github.com/windicss/windicss-webpack-plugin", 19 | "bugs": "https://github.com/windicss/windicss-webpack-plugin/issues", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/windicss/windicss-webpack-plugin" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "scripts": { 28 | "release": "bumpp package.json --commit --push --tag", 29 | "build": "unbuild", 30 | "stub": "unbuild --stub", 31 | "test": "vitest", 32 | "lint": "eslint \"{src,test}/**/*.{ts,vue,json,yml}\"", 33 | "lint:fix": "npm run lint -- --fix", 34 | "dev:craco": "yarn build && cd example/craco && yarn start", 35 | "dev:svelte": "yarn build && cd example/svelte && yarn dev", 36 | "dev:next": "yarn build && cd example/next && yarn dev", 37 | "dev:nuxt": "yarn build && cd example/nuxt && yarn dev", 38 | "build:nuxt": "yarn build && nuxt build example/nuxt", 39 | "start:nuxt": "yarn build && nuxt start example/nuxt", 40 | "dev:vue2": "yarn build && cd example/vue2 && yarn serve", 41 | "dev:vue3": "yarn build && cd example/vue3 && yarn serve", 42 | "dev:vue-nx": "yarn build && cd example/vue-cli-next && yarn serve" 43 | }, 44 | "dependencies": { 45 | "@windicss/plugin-utils": "^1.9.1", 46 | "debug": "^4.3.4", 47 | "get-port": "^6.1.2", 48 | "loader-utils": "^2.0.0", 49 | "lodash": "^4.17.21", 50 | "pathe": "^1.1.0", 51 | "webpack-virtual-modules": "^0.5.0", 52 | "windicss": "^3.5.6" 53 | }, 54 | "devDependencies": { 55 | "@antfu/eslint-config": "^0.42.0", 56 | "@babel/preset-env": "^7.20.2", 57 | "@babel/preset-react": "^7.18.6", 58 | "@intlify/vue-i18n-loader": "^4.2.0", 59 | "@types/color-string": "^1.5.0", 60 | "@types/debug": "^4.1.7", 61 | "@types/loader-utils": "^2.0.3", 62 | "@types/lodash": "^4.14.191", 63 | "@types/webpack": "^4.41.31", 64 | "babel-loader": "^8.2.3", 65 | "bumpp": "^8.2.1", 66 | "css-loader": "^5.2.7", 67 | "eslint": "^8.49.0", 68 | "less": "^4.1.3", 69 | "less-loader": "^7.3.0", 70 | "postcss-loader": "^5.3.0", 71 | "sass": "^1.58.0", 72 | "sass-loader": "^10.2.0", 73 | "schema-utils": "^3.1.1", 74 | "stylus": "^0.54.8", 75 | "stylus-loader": "^3.0.2", 76 | "typescript": "^5.2.2", 77 | "unbuild": "^2.0.0", 78 | "vite": "^4.1.1", 79 | "vitest": "^0.28.4", 80 | "vue-loader": "^15.9.8", 81 | "vue-style-loader": "^4.1.3", 82 | "vue-template-compiler": "^2.7.14", 83 | "webpack": "^4.46.0" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/runtime/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file was copied from https://github.com/windicss/vite-plugin-windicss/blob/main/packages/vite-plugin-windicss/src/client.ts 3 | */ 4 | 5 | /** 6 | https://github.com/windicss/vite-plugin-windicss/blob/main/LICENSE 7 | 8 | MIT License 9 | 10 | Copyright (c) 2020 Anthony Fu 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | SOFTWARE. 29 | */ 30 | 31 | function post(data: any) { 32 | return fetch('__POST_PATH__', { 33 | method: 'POST', 34 | headers: { 35 | 'Content-Type': 'application/json', 36 | }, 37 | body: JSON.stringify(data), 38 | }) 39 | } 40 | 41 | function include(set: Set, v: T[] | Set) { 42 | for (const i of v) 43 | set.add(i) 44 | } 45 | 46 | // eslint-disable-next-line no-console 47 | console.log( 48 | '%c[windicss] devtools support enabled %c\nread more at https://windicss.org', 49 | 'background:#0ea5e9; color:white; padding: 1px 4px; border-radius: 3px;', 50 | '', 51 | ) 52 | 53 | const visitedClasses = new Set() 54 | const pendingClasses = new Set() 55 | 56 | let _timer: number | undefined 57 | 58 | function schedule() { 59 | if (_timer != null) 60 | clearTimeout(_timer) 61 | _timer = setTimeout(() => { 62 | if (pendingClasses.size) { 63 | post({ type: 'add-classes', data: Array.from(pendingClasses) }) 64 | include(visitedClasses, pendingClasses) 65 | pendingClasses.clear() 66 | } 67 | }, 10) as any 68 | } 69 | 70 | const mutationObserver = new MutationObserver((mutations) => { 71 | mutations.forEach((mutation) => { 72 | if (mutation.attributeName === 'class' && mutation.target) { 73 | Array.from((mutation.target as Element).classList || []) 74 | .forEach((i) => { 75 | if (!visitedClasses.has(i)) 76 | pendingClasses.add(i) 77 | }) 78 | schedule() 79 | } 80 | }) 81 | }) 82 | 83 | mutationObserver.observe(document.documentElement || document.body, { 84 | childList: true, 85 | subtree: true, 86 | attributes: true, 87 | }) 88 | -------------------------------------------------------------------------------- /src/core/server.ts: -------------------------------------------------------------------------------- 1 | import http from 'node:http' 2 | import { resolve } from 'node:path' 3 | import type { IncomingMessage } from 'node:http' 4 | import type { Options } from 'get-port' 5 | import type { Compiler } from 'webpack' 6 | import type { WindiCSSWebpackPluginOptions } from '../types' 7 | import { DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT, DEVTOOLS_POST_PATH, DEVTOOLS_VIRTUAL_MODULE } from './constants' 8 | import { getChangedModuleNames, isDev } from './utils' 9 | 10 | const getPort = (options: Options) => import('get-port').then(({ default: getPort }) => getPort(options)) 11 | 12 | function getBodyJson(req: IncomingMessage) { 13 | return new Promise((resolve, reject) => { 14 | let body = '' 15 | req.on('data', chunk => body += chunk) 16 | req.on('error', reject) 17 | req.on('end', () => { 18 | try { 19 | resolve(JSON.parse(body) || {}) 20 | } 21 | catch (e) { 22 | reject(e) 23 | } 24 | }) 25 | }) 26 | } 27 | 28 | function updateCSS(compiler: Compiler) { 29 | const names = getChangedModuleNames(compiler.$windi) 30 | 31 | // Use core/dev-tools-update.js to trigger regeneration of css, 'all-modules' will be slower. 32 | compiler.$windi.dirty.add(resolve(__dirname, './core/dev-tools-update.js')) 33 | 34 | compiler.$windi.invalidateCssModules(DEVTOOLS_VIRTUAL_MODULE, names) 35 | } 36 | 37 | export default class Server { 38 | server: http.Server 39 | host: string 40 | port: number 41 | _listen: boolean 42 | 43 | constructor(compiler: Compiler, options: WindiCSSWebpackPluginOptions['server']) { 44 | this.host = options?.host ?? DEFAULT_SERVER_HOST 45 | this.port = options?.port ?? DEFAULT_SERVER_PORT 46 | this.server = http.createServer(async (req, res) => { 47 | res.setHeader('Access-Control-Allow-Origin', '*') 48 | res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS') 49 | res.setHeader('Access-Control-Allow-Headers', 'Content-Type') 50 | if (req.url === DEVTOOLS_POST_PATH && req.method === 'POST') { 51 | try { 52 | const data = await getBodyJson(req) 53 | let changed = false 54 | switch (data.type) { 55 | case 'add-classes': 56 | changed = compiler.$windi.addClasses(data.data || []) 57 | } 58 | if (changed && this._listen) 59 | updateCSS(compiler) 60 | 61 | res.statusCode = 200 62 | res.end() 63 | } 64 | catch (err) { 65 | res.statusCode = 500 66 | res.end() 67 | } 68 | } 69 | else { 70 | res.statusCode = 200 71 | res.end() 72 | } 73 | }) 74 | this._listen = false 75 | } 76 | 77 | async ensureStart() { 78 | if (!this._listen && isDev()) { 79 | this.port = await getPort({ port: this.port }) 80 | this.server.listen(this.port, this.host, () => { 81 | this._listen = true 82 | // TODO: In webpack 5, use compiler.hooks.shutdown instead 83 | process.once('exit', () => { 84 | this.close() 85 | }) 86 | }) 87 | } 88 | return this 89 | } 90 | 91 | close() { 92 | if (this._listen) 93 | this.server.close() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /example/next/pages/index.jsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import styles from '../styles/Home.module.css' 3 | 4 | export default function Home() { 5 | return ( 6 |
7 | 8 | Create Next App 9 | 10 | 11 | 12 |
13 |

14 |
15 | Should be Yellow 16 |
17 | Welcome to Next.js! 18 |

19 | 20 |

21 | Get started by editing{' '} 22 | pages/index.js 23 | 24 |

25 |

go to test

26 | 27 | 75 |
76 | 77 | 87 |
88 | ) 89 | } 90 | -------------------------------------------------------------------------------- /example/craco/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

windicss-webpack-plugin

2 | 3 |

:leaves: Windi CSS for webpack️
4 | Next generation utility-first CSS framework. 5 |

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 |

15 | 16 | ⚠️ Consider using [UnoCSS](https://github.com/unocss/unocss) instead, 17 | it's a rebuild of the WindiCSS core with a lot of improvements and new features. 18 | 19 |

20 | 21 | 22 | 28 | 29 |
23 |
24 | Status: Stable - Maintenance only
25 | Made possible by my Sponsor Program 💖
Follow me @harlan_zw 🐦

26 | 27 |
30 |

31 | 32 | ## Features 33 | 34 | - 🧩 On-demand CSS utilities (Compatible with Tailwind CSS v2) and preflights 35 | - 🍃 Load configurations from `tailwind.config.js` 36 | - 🤝 Framework-agnostic: Vue CLI, Nuxt, Next, UmiJS, etc! 37 | - 📄 Use [directives](https://windicss.org/features/directives.html) in any CSS (SCSS, LESS, etc) `@apply`, `@variants`, `@screen`, `@layer`, `theme()`, 38 | - 🎳 Support Utility Groups - e.g. `bg-gray-200 hover:(bg-gray-100 text-red-300)` 39 | 40 | ## Documentation 41 | 42 | Read the [documentation](https://windicss.org/integrations/webpack.html) for more details. 43 | 44 | ## New Webpack Plugin Features 45 | 46 | **Design in DevTools mode** 47 | 48 | Add the import with your existing windi imports and you'll have autocompletion in your Chrome DevTools! See ["Design in DevTools"](https://windicss.org/integrations/vite.html#design-in-devtools) for 49 | more information. 50 | 51 | ```js 52 | import 'virtual:windi-devtools' 53 | ``` 54 | 55 | 56 | 57 | Thanks [await-ovo](https://github.com/await-ovo)! 58 | 59 | ## New Windi v3.0 Features 60 | 61 | ### [Attributify Mode](https://windicss.org/posts/v30.html#attributify-mode) 62 | 63 | Enabled it by 64 | 65 | ```ts 66 | // windi.config.ts 67 | export default { 68 | attributify: true 69 | } 70 | ``` 71 | 72 | And use them as you would like: 73 | 74 | ```html 75 | 84 | ``` 85 | 86 | ### [Alias Config](https://windicss.org/posts/v30.html#alias-config) 87 | 88 | ```ts 89 | // windi.config.ts 90 | export default { 91 | alias: { 92 | 'hstack': 'flex items-center', 93 | 'vstack': 'flex flex-col', 94 | 'icon': 'w-6 h-6 fill-current', 95 | 'app': 'text-red', 96 | 'app-border': 'border-gray-200 dark:border-dark-300', 97 | }, 98 | } 99 | ``` 100 | 101 | ## Sponsors 102 | 103 |

104 | 105 | 106 | 107 |

108 | 109 | ## License 110 | 111 | MIT License © 2022 - Present [Harlan Wilton](https://github.com/harlan-zw) 112 | -------------------------------------------------------------------------------- /src/loaders/windicss-template.ts: -------------------------------------------------------------------------------- 1 | import compileTemplate from 'lodash/template' 2 | import defaults from 'lodash/defaults' 3 | import loaderUtils from 'loader-utils' 4 | import type { loader } from 'webpack' 5 | import debug from '../core/debug' 6 | import { def, isJsx, transformCSS } from '../core/utils' 7 | 8 | function WindicssTemplate( 9 | this: loader.LoaderContext, 10 | source: string, 11 | ): string { 12 | if (!this._compiler) 13 | return source 14 | 15 | this.cacheable(true) 16 | // @ts-expect-error untyped 17 | const service = this._compiler.$windi 18 | 19 | if (!service) 20 | return source 21 | 22 | /* 23 | * Via the pitcher loader we can transfer post-interpreted CSS 24 | */ 25 | if (this.resource.indexOf('type=style') > 0) 26 | return transformCSS(service, source, this.resource) 27 | 28 | const hasHtmlWebpackPlugin = this.loaders.filter((loader) => { 29 | // loader name as unresolved module 30 | return (loader.loader && loader.loader.indexOf('html-webpack-plugin') > 0) 31 | // resolved loader name as path 32 | || (loader.path && loader.path.indexOf('html-webpack-plugin') > 0) 33 | }).length > 0 34 | 35 | if (hasHtmlWebpackPlugin) { 36 | /* 37 | * Because the html-webpack-plugin doesn't support multiple loaders, we need to replicate the behaviour of the plugin 38 | * here, this is pretty hacky but haven't been able to find a solution. @todo find a better solution 39 | * 40 | * Source: html-webpack-plugin/lib/loader.js 41 | */ 42 | const options = this.query !== '' ? loaderUtils.parseQuery(this.query) : {} 43 | const template = compileTemplate(source, defaults(options, { variable: 'data' })) 44 | // Require !!lodash - using !! will disable all loaders (e.g. babel) 45 | return `var _ = require(${loaderUtils.stringifyRequest(this, `!!${require.resolve('lodash')}`)});` 46 | + 'module.exports = function (templateParams) { with(templateParams) {' 47 | // Execute the lodash template 48 | + `return (${template.source})();` 49 | + '}}' 50 | } 51 | 52 | let output = source 53 | try { 54 | const templateWithTransformedCSS = source.replace(/(.*?)<\/style>/gms, (match, meta, css) => { 55 | // bail out, return the original match 56 | if (meta.includes('sass') || meta.includes('stylus') || meta.includes('less')) { 57 | debug.loader('Template has unsupported block, skipping resource', this.resource) 58 | return match 59 | } 60 | // for jsx styles we need to replace the contents of template strings 61 | if (isJsx(css)) { 62 | let m, transformedCSS 63 | const jsxMatcher = /{`(.*)`}/gms 64 | while ((m = jsxMatcher.exec(css)) !== null) { 65 | // This is necessary to avoid infinite loops with zero-width matches 66 | if (m.index === jsxMatcher.lastIndex) 67 | jsxMatcher.lastIndex++ 68 | 69 | // The result can be accessed through the `m`-variable. 70 | m.forEach((match, groupIndex) => { 71 | if (groupIndex === 1) { 72 | const transformedJSXCSS = transformCSS(service, match, this.resource) 73 | transformedCSS = `\n{\`${transformedJSXCSS}\n\`}` 74 | debug.loader('jsx transformed', transformedCSS) 75 | } 76 | }) 77 | } 78 | return def(transformedCSS, match) 79 | } 80 | const transformedCSS = transformCSS(service, css, this.resource) 81 | return `${transformedCSS}` 82 | }) 83 | debug.loader('Transformed template ', this.resource) 84 | const transformed = service.transformGroups(templateWithTransformedCSS) 85 | if (transformed) 86 | output = transformed.code 87 | else 88 | output = templateWithTransformedCSS 89 | } 90 | catch (e) { 91 | this.emitWarning(`[WindiCSS] Failed to transform groups and css for template: ${this.resource}.`) 92 | } 93 | return output 94 | } 95 | 96 | export default WindicssTemplate 97 | -------------------------------------------------------------------------------- /src/loaders/virtual-module.ts: -------------------------------------------------------------------------------- 1 | import fs, { readFileSync } from 'node:fs' 2 | import type { loader } from 'webpack' 3 | import { defaultConfigureFiles } from '@windicss/plugin-utils' 4 | import type { LayerName } from '@windicss/plugin-utils' 5 | import { MODULE_ID_VIRTUAL_TEST } from '../core/constants' 6 | import debug from '../core/debug' 7 | import { def } from '../core/utils' 8 | 9 | async function VirtualModule( 10 | this: loader.LoaderContext, 11 | source: string, 12 | ): Promise { 13 | const callback = this.async()! 14 | if (!this._compiler) { 15 | callback(null, source) 16 | return 17 | } 18 | this.cacheable(false) 19 | // @ts-expect-error untyped 20 | const service = this._compiler.$windi 21 | const match = this.resource.match(MODULE_ID_VIRTUAL_TEST) 22 | if (!service || !match) { 23 | const error = new Error(`Failed to match the resource "${this.resource}" to a WindiCSS virtual module.`) 24 | this.emitError(error) 25 | callback(error, source) 26 | return 27 | } 28 | 29 | const layer = (match[1] as LayerName | undefined) || undefined 30 | const isBoot = source.indexOf('(boot)') > 0 31 | 32 | debug.loader(`Generating "${this.resource}" using layer "${layer}${isBoot ? '" as boot ' : ' as hmr'}`) 33 | 34 | const generateCSS = async (layer: LayerName | undefined) => { 35 | try { 36 | // avoid duplicate scanning on HMR 37 | if (service.scanned && service.options.enableScan) 38 | service.options.enableScan = false 39 | 40 | const css = (await service.generateCSS(layer)).replace('(boot)', '') 41 | service.virtualModules.set(def(layer, 'all'), css) 42 | callback(null, css) 43 | } 44 | catch (e: any) { 45 | const error = JSON.stringify(e, null, 2) 46 | this.emitError(`[Windi CSS] Failed to generate CSS. Error: ${error}`) 47 | callback(e, `${source}\n` + `/* Error: ${error}*/`) 48 | } 49 | } 50 | 51 | if (isBoot) { 52 | await generateCSS(layer) 53 | return 54 | } 55 | 56 | // Make sure we're hot 57 | const dirtyFiles = Array.from(service.dirty)! 58 | if (dirtyFiles.length === 0) { 59 | callback(null, source) 60 | return 61 | } 62 | 63 | // Need to do a complete re-scan, we got a null entry on the watcher so we know a file updated but don't know which one 64 | if (service.dirty.has('all-modules')) { 65 | const contents = await Promise.all( 66 | [...(await service.getFiles())] 67 | .filter(id => service.isDetectTarget(id)) 68 | .map(async id => [await fs.promises.readFile(id, 'utf-8'), id]), 69 | ) 70 | 71 | await Promise.all(contents.map( 72 | async ([content, id]) => { 73 | if (service.isCssTransformTarget(id)) 74 | return service.transformCSS(content, id) 75 | else 76 | return service.extractFile(content, id, true) 77 | }, 78 | )) 79 | } 80 | else { 81 | // @ts-expect-error untyped 82 | const configFileUpdated = dirtyFiles.filter((id: string) => { 83 | return defaultConfigureFiles.filter((config) => { 84 | return id.endsWith(config) 85 | }).length > 0 86 | }).length > 0 87 | // If it is a config update we init the service again 88 | if (configFileUpdated) { 89 | service.clearCache() 90 | await service.init() 91 | } 92 | else { 93 | // Get all of our dirty files and parse their content 94 | const contents = await Promise.all( 95 | dirtyFiles.map((id) => { 96 | return { 97 | data: readFileSync(id as string, { encoding: 'utf-8' }), 98 | id, 99 | } 100 | }), 101 | ) 102 | 103 | // Extract the content into windicss service 104 | for (const content of contents) { 105 | try { 106 | await service.extractFile(content.data, content.id, service.options.transformGroups) 107 | } 108 | catch (e) { 109 | this.emitWarning(`[Windi CSS] Failed to extract classes from resource: ${content.id}.`) 110 | } 111 | } 112 | } 113 | } 114 | // Don't process the same files until they're dirty again 115 | service.dirty.clear() 116 | 117 | await generateCSS(layer) 118 | } 119 | 120 | export default VirtualModule 121 | -------------------------------------------------------------------------------- /example/vue3-storybook/src/stories/Introduction.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | import Code from './assets/code-brackets.svg'; 3 | import Colors from './assets/colors.svg'; 4 | import Comments from './assets/comments.svg'; 5 | import Direction from './assets/direction.svg'; 6 | import Flow from './assets/flow.svg'; 7 | import Plugin from './assets/plugin.svg'; 8 | import Repo from './assets/repo.svg'; 9 | import StackAlt from './assets/stackalt.svg'; 10 | 11 | 12 | 13 | 116 | 117 | # Welcome to Storybook 118 | 119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context. 120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA. 121 | 122 | Browse example stories now by navigating to them in the sidebar. 123 | View their code in the `src/stories` directory to learn how they work. 124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. 125 | 126 |
Configure
127 | 128 | 174 | 175 |
Learn
176 | 177 | 207 | 208 |
209 | TipEdit the Markdown in{' '} 210 | src/stories/Introduction.stories.mdx 211 |
212 | --------------------------------------------------------------------------------