@weapp-tailwindcss/postcss 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md ADDED
@@ -0,0 +1,9 @@
1
+ # @weapp-tailwindcss/postcss
2
+
3
+ > English | [简体中文](./README.md)
4
+
5
+ This package is the CSS processing core of weapp-tailwindcss. It handles PostCSS AST transforms, selector compatibility, platform differences, and Tailwind output post-processing for mini programs.
6
+
7
+ ## Website
8
+
9
+ For setup guides, configuration references, and framework examples, see the [official weapp-tailwindcss documentation](https://tw.icebreaker.top).
package/README.md CHANGED
@@ -1,99 +1,9 @@
1
- <p align="center">
1
+ # @weapp-tailwindcss/postcss
2
2
 
3
- <a href="https://tw.icebreaker.top">
3
+ > 简体中文 | [English](./README.en.md)
4
4
 
5
- <img src="./assets/logo.png" alt="weapp-tailwindcss-logo" width="128">
6
- </a>
5
+ 这个包是 weapp-tailwindcss 的 CSS 处理核心,负责小程序端的 PostCSS AST 转换、选择器兼容、平台差异处理和 Tailwind 输出后处理。
7
6
 
8
- <br>
7
+ ## 官网
9
8
 
10
- <h1 align="center">weapp-tailwindcss</h1>
11
-
12
- </p>
13
-
14
- > 简体中文(zh-cn) | [English](./README_en.md)
15
-
16
- ![star](https://badgen.net/github/stars/sonofmagic/weapp-tailwindcss)
17
- ![dm0](https://badgen.net/npm/dm/weapp-tailwindcss)
18
- ![license](https://badgen.net/npm/license/weapp-tailwindcss)
19
- [![test](https://github.com/sonofmagic/weapp-tailwindcss/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/sonofmagic/weapp-tailwindcss/actions/workflows/test.yml)
20
- [![codecov](https://codecov.io/gh/sonofmagic/weapp-tailwindcss/branch/main/graph/badge.svg?token=zn05qXYznt)](https://codecov.io/gh/sonofmagic/weapp-tailwindcss)
21
-
22
- > [!NOTE]
23
- > 降低开发维护成本,提升开发效率的 `小程序` `tailwindcss` 全方面解决方案
24
- >
25
- > `weapp-tailwindcss@4.2.x` 现已支持 `uni-app x` 同时构建 `Web`,`小程序`,`安卓`,`IOS`,`鸿蒙`,详见 [**uni-app x 专题**](https://tw.icebreaker.top/docs/uni-app-x)
26
-
27
- \[[文档地址](https://tw.icebreaker.top)\] \| \[[备用文档地址](https://ice-tw.netlify.app/)\] \| \[[加入技术交流群](https://tw.icebreaker.top/docs/community/group)\]
28
-
29
- - [特性](#特性)
30
- - [版本对应](#版本对应)
31
- - [安装与使用方式](#安装与使用方式)
32
- - [生态和解决方案](#生态和解决方案)
33
- - [常见问题](#常见问题)
34
- - [各个框架的模板](#各个框架的模板)
35
- - [旧版本迁移指南](#旧版本迁移指南)
36
- - [配置项参考](#配置项参考)
37
- - [Contribute](#contribute)
38
- - [License](#license)
39
- - [Star History](#star-history)
40
- - [Related projects](#related-projects)
41
- - [weapp-vite](#weapp-vite)
42
-
43
- ## 特性
44
-
45
- | 不仅仅是`webpack` | 主流框架与原生开发支持 |
46
- | --------------------------------------------------- | ----------------------------------------------- |
47
- | ![wepback+vite+gulp](./assets/weapp-tw-plugins.png) | ![frameworks](./assets/weapp-tw-frameworks.png) |
48
-
49
- 核心插件支持 `webpack`/`vite`/`rspack`/`rollup`/`rolldown`/`gulp` 为基底的框架类小程序开发,涵盖了市面上几乎所有的主流的开发框架。
50
-
51
- 也支持直接从各个开发者工具中,直接创建的原生小程序应用。
52
-
53
- 这些插件能够自动识别并精确处理所有 `tailwindcss` 的工具类来适配小程序环境。
54
-
55
- ## 版本对应
56
-
57
- 目前,`weapp-tailwindcss` 的 `5.x` 版本
58
-
59
- - 支持最新版本的 `tailwindcss v4` 和 `v3`。
60
- - 支持 `webpack5`、`vite`、`rspack`、`rollup`、`rolldown` 和 `gulp` 这些打包工具,也支持纯 `Nodejs` API 的方式,集成到你自己的构建工具中。
61
-
62
- > `weapp-tailwindcss@5` 面向 Tailwind CSS v3/v4 和现代构建链路,不再内置 Webpack4、PostCSS7、Tailwind CSS v2 兼容入口。`weapp-tailwindcss@5` 需要 `nodejs` 版本 `^20.19.0 || >=22.12.0`,建议安装 `nodejs` 的 `LTS` 版本,详见 [nodejs/release](https://github.com/nodejs/release)
63
-
64
- ## [安装与使用方式](https://tw.icebreaker.top/docs/quick-start/install)
65
-
66
- ## [生态和解决方案](https://tw.icebreaker.top/docs/community/templates)
67
-
68
- ## [常见问题](https://tw.icebreaker.top/docs/issues/)
69
-
70
- ## [各个框架的模板](https://tw.icebreaker.top/docs/community/templates)
71
-
72
- ## [旧版本迁移指南](https://tw.icebreaker.top/docs/migrations/v2)
73
-
74
- ## [配置项参考](https://tw.icebreaker.top/docs/api/interfaces/UserDefinedOptions)
75
-
76
- ## Contribute
77
-
78
- 我们邀请你来贡献和帮助改进 `weapp-tailwindcss` 💚💚💚
79
-
80
- 以下有几个方式可以参与:
81
-
82
- - 报告错误:如果您遇到任何错误或问题,请提`issue`并提供完善的错误信息和复现方式。
83
- - 建议:有增强 `weapp-tailwindcss` 的想法吗?请提 `issue` 来分享您的建议。
84
- - 文档:如果您对文档有更好的见解或者更棒的修辞方式,欢迎 `pr`。
85
- - 代码:任何人的代码都不是完美的,我们欢迎你通过 `pr` 给代码提供更好的质量与活力。
86
-
87
- ## License
88
-
89
- [MIT](./LICENSE)
90
-
91
- ## Star History
92
-
93
- [![Star History Chart](https://api.star-history.com/svg?repos=sonofmagic/weapp-tailwindcss&type=Date)](https://star-history.com/#sonofmagic/weapp-tailwindcss&Date)
94
-
95
- ## Related projects
96
-
97
- ### weapp-vite
98
-
99
- [weapp-vite](https://vite.icebreaker.top/): 把现代化的开发模式带入小程序开发!
9
+ 更多接入方式、配置说明和框架示例见 [weapp-tailwindcss 官方文档](https://tw.icebreaker.top)。
@@ -7,6 +7,7 @@ export interface FinalizeMiniProgramCssOptions {
7
7
  }
8
8
  export declare function collectPreflightRules(root: postcss.Root, options?: {
9
9
  preservePseudoContentInit?: boolean;
10
+ cssPreflight?: CssPreflightOptions | undefined;
10
11
  }): postcss.Rule[];
11
12
  export declare function insertHoistedRules(root: postcss.Root, rules: postcss.Rule[], anchor?: postcss.Comment): void;
12
13
  export declare function hoistTailwindPreflightBase(css: string): string;
package/dist/index.js CHANGED
@@ -7472,6 +7472,7 @@ function removeUnsupportedModernColorDeclarations(root) {
7472
7472
  //#region src/compat/mini-program-css/finalize.ts
7473
7473
  const HOIST_ANCHOR_COMMENT = "__weapp_tailwindcss_base_anchor__";
7474
7474
  const TAILWIND_V4_BANNER_RE = /\/\*!\s*tailwindcss v4\./;
7475
+ const GENERATOR_PLACEHOLDER_COMMENT_RE = /^\s*(?:!\s*)?weapp-tailwindcss generator-placeholder\s*$/i;
7475
7476
  const MINI_PROGRAM_PSEUDO_CONTENT_SCOPE_SELECTOR = "::before,\n::after";
7476
7477
  const MINI_PROGRAM_PSEUDO_CONTENT_SELECTORS = new Set(["::before", "::after"]);
7477
7478
  function createPseudoContentInitRule() {
@@ -7482,6 +7483,26 @@ function createPseudoContentInitRule() {
7482
7483
  });
7483
7484
  return rule;
7484
7485
  }
7486
+ function applyConfiguredPreflightDeclarations(rule, cssPreflight) {
7487
+ if (!cssPreflight || typeof cssPreflight !== "object") return;
7488
+ const configuredProps = new Set(Object.keys(cssPreflight));
7489
+ rule.walkDecls((decl) => {
7490
+ if (!configuredProps.has(decl.prop)) return;
7491
+ const value = cssPreflight[decl.prop];
7492
+ if (value === false) {
7493
+ decl.remove();
7494
+ return;
7495
+ }
7496
+ decl.value = value.toString();
7497
+ });
7498
+ for (const [prop, value] of Object.entries(cssPreflight)) {
7499
+ if (value === false || rule.nodes?.some((node) => node.type === "decl" && node.prop === prop)) continue;
7500
+ rule.append({
7501
+ prop,
7502
+ value: value.toString()
7503
+ });
7504
+ }
7505
+ }
7485
7506
  function collectPreflightRules(root, options = {}) {
7486
7507
  const preflightNodes = [];
7487
7508
  for (const node of root.nodes ?? []) if (isMiniProgramPreflightRule(node)) preflightNodes.push(node);
@@ -7497,7 +7518,10 @@ function collectPreflightRules(root, options = {}) {
7497
7518
  const selectors = getRuleSelectors(rule);
7498
7519
  const hasElementSelector = selectors.some((selector) => selector === "view" || selector === "text");
7499
7520
  if (selectors.length > 0 && selectors.every((selector) => MINI_PROGRAM_PSEUDO_CONTENT_SELECTORS.has(selector))) rule.selector = MINI_PROGRAM_PSEUDO_CONTENT_SCOPE_SELECTOR;
7500
- else if (hasElementSelector && selectors.every((selector) => MINI_PROGRAM_ELEMENT_SCOPE_SELECTORS.has(selector))) rule.selector = MINI_PROGRAM_ELEMENT_SCOPE_SELECTOR;
7521
+ else if (hasElementSelector && selectors.every((selector) => MINI_PROGRAM_ELEMENT_SCOPE_SELECTORS.has(selector))) {
7522
+ rule.selector = MINI_PROGRAM_ELEMENT_SCOPE_SELECTOR;
7523
+ applyConfiguredPreflightDeclarations(rule, options.cssPreflight);
7524
+ }
7501
7525
  }
7502
7526
  const nonEmptyPreflightRules = clonedPreflightRules.filter((rule) => (rule.nodes?.length ?? 0) > 0);
7503
7527
  const preflightRules = [...options.preservePseudoContentInit ? [createPseudoContentInitRule()] : [], ...nonEmptyPreflightRules];
@@ -7587,21 +7611,41 @@ function insertHoistedRules(root, rules, anchor) {
7587
7611
  function mergeEquivalentHoistedRules(rules) {
7588
7612
  const mergedRules = [];
7589
7613
  const ruleBySelector = /* @__PURE__ */ new Map();
7614
+ const propsBySelector = /* @__PURE__ */ new Map();
7590
7615
  for (const rule of rules) {
7591
7616
  const key = getSortedRuleSelectorKey(rule);
7592
7617
  const existingRule = ruleBySelector.get(key);
7593
7618
  if (existingRule) {
7594
- existingRule.append(...(rule.nodes ?? []).map((node) => node.clone()));
7619
+ const existingProps = propsBySelector.get(key) ?? /* @__PURE__ */ new Set();
7620
+ const nextNodes = (rule.nodes ?? []).filter((node) => {
7621
+ if (node.type !== "decl") return true;
7622
+ if (existingProps.has(node.prop)) return false;
7623
+ existingProps.add(node.prop);
7624
+ return true;
7625
+ });
7626
+ existingRule.append(...nextNodes.map((node) => node.clone()));
7627
+ propsBySelector.set(key, existingProps);
7595
7628
  continue;
7596
7629
  }
7597
7630
  ruleBySelector.set(key, rule);
7631
+ propsBySelector.set(key, new Set((rule.nodes ?? []).flatMap((node) => node.type === "decl" ? [node.prop] : [])));
7598
7632
  mergedRules.push(rule);
7599
7633
  }
7600
7634
  return mergedRules;
7601
7635
  }
7602
7636
  function unwrapTailwindSourceMedia(root) {
7603
7637
  root.walkAtRules("media", (atRule) => {
7604
- if (atRule.params.startsWith("source(") && atRule.nodes && atRule.nodes.length > 0) atRule.replaceWith(...atRule.nodes);
7638
+ if (!atRule.params.startsWith("source(")) return;
7639
+ if (atRule.nodes && atRule.nodes.length > 0) atRule.replaceWith(...atRule.nodes);
7640
+ else atRule.remove();
7641
+ });
7642
+ }
7643
+ function removeTailwindGenerationDirectives(root) {
7644
+ root.walkComments((comment) => {
7645
+ if (GENERATOR_PLACEHOLDER_COMMENT_RE.test(comment.text)) comment.remove();
7646
+ });
7647
+ root.walkAtRules((atRule) => {
7648
+ if (atRule.name === "config" || atRule.name === "source" || atRule.name === "tailwind" || atRule.name === "reference" || atRule.name === "plugin") atRule.remove();
7605
7649
  });
7606
7650
  }
7607
7651
  function finalizeMiniProgramCssRoot(root, options = {}) {
@@ -7609,6 +7653,7 @@ function finalizeMiniProgramCssRoot(root, options = {}) {
7609
7653
  const tailwindcssV4DefaultNodes = shouldInjectTailwindcssV4Defaults ? createMissingCssVarsV4Nodes(root, collectUsedTailwindcssV4Variables(root)) : [];
7610
7654
  removeUnsupportedCascadeLayers(root);
7611
7655
  unwrapTailwindSourceMedia(root);
7656
+ removeTailwindGenerationDirectives(root);
7612
7657
  root.walkAtRules("property", (atRule) => {
7613
7658
  atRule.remove();
7614
7659
  });
package/dist/index.mjs CHANGED
@@ -7484,6 +7484,7 @@ function removeUnsupportedModernColorDeclarations(root) {
7484
7484
  //#region src/compat/mini-program-css/finalize.ts
7485
7485
  const HOIST_ANCHOR_COMMENT = "__weapp_tailwindcss_base_anchor__";
7486
7486
  const TAILWIND_V4_BANNER_RE = /\/\*!\s*tailwindcss v4\./;
7487
+ const GENERATOR_PLACEHOLDER_COMMENT_RE = /^\s*(?:!\s*)?weapp-tailwindcss generator-placeholder\s*$/i;
7487
7488
  const MINI_PROGRAM_PSEUDO_CONTENT_SCOPE_SELECTOR = "::before,\n::after";
7488
7489
  const MINI_PROGRAM_PSEUDO_CONTENT_SELECTORS = new Set(["::before", "::after"]);
7489
7490
  function createPseudoContentInitRule() {
@@ -7494,6 +7495,26 @@ function createPseudoContentInitRule() {
7494
7495
  });
7495
7496
  return rule;
7496
7497
  }
7498
+ function applyConfiguredPreflightDeclarations(rule, cssPreflight) {
7499
+ if (!cssPreflight || typeof cssPreflight !== "object") return;
7500
+ const configuredProps = new Set(Object.keys(cssPreflight));
7501
+ rule.walkDecls((decl) => {
7502
+ if (!configuredProps.has(decl.prop)) return;
7503
+ const value = cssPreflight[decl.prop];
7504
+ if (value === false) {
7505
+ decl.remove();
7506
+ return;
7507
+ }
7508
+ decl.value = value.toString();
7509
+ });
7510
+ for (const [prop, value] of Object.entries(cssPreflight)) {
7511
+ if (value === false || rule.nodes?.some((node) => node.type === "decl" && node.prop === prop)) continue;
7512
+ rule.append({
7513
+ prop,
7514
+ value: value.toString()
7515
+ });
7516
+ }
7517
+ }
7497
7518
  function collectPreflightRules(root, options = {}) {
7498
7519
  const preflightNodes = [];
7499
7520
  for (const node of root.nodes ?? []) if (isMiniProgramPreflightRule(node)) preflightNodes.push(node);
@@ -7509,7 +7530,10 @@ function collectPreflightRules(root, options = {}) {
7509
7530
  const selectors = getRuleSelectors(rule);
7510
7531
  const hasElementSelector = selectors.some((selector) => selector === "view" || selector === "text");
7511
7532
  if (selectors.length > 0 && selectors.every((selector) => MINI_PROGRAM_PSEUDO_CONTENT_SELECTORS.has(selector))) rule.selector = MINI_PROGRAM_PSEUDO_CONTENT_SCOPE_SELECTOR;
7512
- else if (hasElementSelector && selectors.every((selector) => MINI_PROGRAM_ELEMENT_SCOPE_SELECTORS.has(selector))) rule.selector = MINI_PROGRAM_ELEMENT_SCOPE_SELECTOR;
7533
+ else if (hasElementSelector && selectors.every((selector) => MINI_PROGRAM_ELEMENT_SCOPE_SELECTORS.has(selector))) {
7534
+ rule.selector = MINI_PROGRAM_ELEMENT_SCOPE_SELECTOR;
7535
+ applyConfiguredPreflightDeclarations(rule, options.cssPreflight);
7536
+ }
7513
7537
  }
7514
7538
  const nonEmptyPreflightRules = clonedPreflightRules.filter((rule) => (rule.nodes?.length ?? 0) > 0);
7515
7539
  const preflightRules = [...options.preservePseudoContentInit ? [createPseudoContentInitRule()] : [], ...nonEmptyPreflightRules];
@@ -7599,21 +7623,41 @@ function insertHoistedRules(root, rules, anchor) {
7599
7623
  function mergeEquivalentHoistedRules(rules) {
7600
7624
  const mergedRules = [];
7601
7625
  const ruleBySelector = /* @__PURE__ */ new Map();
7626
+ const propsBySelector = /* @__PURE__ */ new Map();
7602
7627
  for (const rule of rules) {
7603
7628
  const key = getSortedRuleSelectorKey(rule);
7604
7629
  const existingRule = ruleBySelector.get(key);
7605
7630
  if (existingRule) {
7606
- existingRule.append(...(rule.nodes ?? []).map((node) => node.clone()));
7631
+ const existingProps = propsBySelector.get(key) ?? /* @__PURE__ */ new Set();
7632
+ const nextNodes = (rule.nodes ?? []).filter((node) => {
7633
+ if (node.type !== "decl") return true;
7634
+ if (existingProps.has(node.prop)) return false;
7635
+ existingProps.add(node.prop);
7636
+ return true;
7637
+ });
7638
+ existingRule.append(...nextNodes.map((node) => node.clone()));
7639
+ propsBySelector.set(key, existingProps);
7607
7640
  continue;
7608
7641
  }
7609
7642
  ruleBySelector.set(key, rule);
7643
+ propsBySelector.set(key, new Set((rule.nodes ?? []).flatMap((node) => node.type === "decl" ? [node.prop] : [])));
7610
7644
  mergedRules.push(rule);
7611
7645
  }
7612
7646
  return mergedRules;
7613
7647
  }
7614
7648
  function unwrapTailwindSourceMedia(root) {
7615
7649
  root.walkAtRules("media", (atRule) => {
7616
- if (atRule.params.startsWith("source(") && atRule.nodes && atRule.nodes.length > 0) atRule.replaceWith(...atRule.nodes);
7650
+ if (!atRule.params.startsWith("source(")) return;
7651
+ if (atRule.nodes && atRule.nodes.length > 0) atRule.replaceWith(...atRule.nodes);
7652
+ else atRule.remove();
7653
+ });
7654
+ }
7655
+ function removeTailwindGenerationDirectives(root) {
7656
+ root.walkComments((comment) => {
7657
+ if (GENERATOR_PLACEHOLDER_COMMENT_RE.test(comment.text)) comment.remove();
7658
+ });
7659
+ root.walkAtRules((atRule) => {
7660
+ if (atRule.name === "config" || atRule.name === "source" || atRule.name === "tailwind" || atRule.name === "reference" || atRule.name === "plugin") atRule.remove();
7617
7661
  });
7618
7662
  }
7619
7663
  function finalizeMiniProgramCssRoot(root, options = {}) {
@@ -7621,6 +7665,7 @@ function finalizeMiniProgramCssRoot(root, options = {}) {
7621
7665
  const tailwindcssV4DefaultNodes = shouldInjectTailwindcssV4Defaults ? createMissingCssVarsV4Nodes(root, collectUsedTailwindcssV4Variables(root)) : [];
7622
7666
  removeUnsupportedCascadeLayers(root);
7623
7667
  unwrapTailwindSourceMedia(root);
7668
+ removeTailwindGenerationDirectives(root);
7624
7669
  root.walkAtRules("property", (atRule) => {
7625
7670
  atRule.remove();
7626
7671
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weapp-tailwindcss/postcss",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "@weapp-tailwindcss/postcss",
5
5
  "author": "ice breaker <1324318532@qq.com>",
6
6
  "license": "MIT",
@@ -65,7 +65,7 @@
65
65
  "postcss-rule-unit-converter": "^0.2.2",
66
66
  "postcss-selector-parser": "~7.1.1",
67
67
  "postcss-value-parser": "^4.2.0",
68
- "@weapp-tailwindcss/postcss-calc": "^1.0.1",
68
+ "@weapp-tailwindcss/postcss-calc": "^1.0.2",
69
69
  "@weapp-tailwindcss/shared": "2.0.0"
70
70
  },
71
71
  "devDependencies": {