@ecopages/postcss-processor 0.2.0-alpha.1 → 0.2.0-alpha.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/CHANGELOG.md +26 -0
- package/package.json +38 -32
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/plugin.d.ts +112 -0
- package/src/plugin.js +354 -0
- package/src/plugin.ts +140 -5
- package/src/postcss-processor.d.ts +48 -0
- package/src/postcss-processor.js +69 -0
- package/src/presets/index.d.ts +6 -0
- package/src/presets/index.js +6 -0
- package/src/presets/tailwind-v3.d.ts +34 -0
- package/src/presets/tailwind-v3.js +26 -0
- package/src/presets/tailwind-v3.ts +19 -8
- package/src/presets/tailwind-v4.d.ts +47 -0
- package/src/presets/tailwind-v4.js +57 -0
- package/src/presets/tailwind-v4.ts +17 -8
- package/src/runtime/css-loader-plugin.d.ts +9 -0
- package/src/runtime/css-loader-plugin.js +28 -0
- package/src/runtime/css-loader.bun.d.ts +9 -0
- package/src/runtime/css-loader.bun.js +22 -0
- package/src/runtime/css-runtime-contract.d.ts +5 -0
- package/src/runtime/css-runtime-contract.js +0 -0
- package/src/test/css/base.css +0 -3
- package/src/test/css/correct.css +0 -3
- package/src/test/css/error.css +0 -3
- package/src/test/css/external-plugins.css +0 -13
- package/src/test/css/import.css +0 -4
- package/src/test/plugin.test.ts +0 -74
- package/src/test/postcss-processor.test.ts +0 -106
- package/src/test/presets.test.ts +0 -140
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getFileAsBuffer } from "../postcss-processor";
|
|
2
|
+
const createBunCssLoaderPlugin = ({ name, filter, transform }) => ({
|
|
3
|
+
name,
|
|
4
|
+
setup(build) {
|
|
5
|
+
build.onLoad({ filter }, async (args) => {
|
|
6
|
+
const rawFile = await getFileAsBuffer(args.path);
|
|
7
|
+
const css = await transform({
|
|
8
|
+
contents: rawFile,
|
|
9
|
+
filePath: args.path
|
|
10
|
+
});
|
|
11
|
+
return {
|
|
12
|
+
exports: {
|
|
13
|
+
default: css
|
|
14
|
+
},
|
|
15
|
+
loader: "object"
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
export {
|
|
21
|
+
createBunCssLoaderPlugin
|
|
22
|
+
};
|
|
File without changes
|
package/src/test/css/base.css
DELETED
package/src/test/css/correct.css
DELETED
package/src/test/css/error.css
DELETED
package/src/test/css/import.css
DELETED
package/src/test/plugin.test.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, afterAll, beforeAll, vi } from 'vitest';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import { PostCssProcessorPlugin } from '../plugin';
|
|
5
|
-
import type { ClientBridge } from '@ecopages/core/adapters/bun/client-bridge';
|
|
6
|
-
import { ConfigBuilder } from '@ecopages/core/config-builder';
|
|
7
|
-
|
|
8
|
-
const TMP_DIR = path.join(__dirname, 'tmp_test_hmr');
|
|
9
|
-
const SRC_DIR = path.join(TMP_DIR, 'src');
|
|
10
|
-
const DIST_DIR = path.join(TMP_DIR, 'dist');
|
|
11
|
-
|
|
12
|
-
describe('PostCssProcessorPlugin HMR', () => {
|
|
13
|
-
beforeAll(() => {
|
|
14
|
-
if (fs.existsSync(TMP_DIR)) {
|
|
15
|
-
fs.rmSync(TMP_DIR, { recursive: true, force: true });
|
|
16
|
-
}
|
|
17
|
-
fs.mkdirSync(SRC_DIR, { recursive: true });
|
|
18
|
-
fs.mkdirSync(DIST_DIR, { recursive: true });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterAll(() => {
|
|
22
|
-
fs.rmSync(TMP_DIR, { recursive: true, force: true });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('handleCssChange should apply transformInput', async () => {
|
|
26
|
-
const cssFile = path.join(SRC_DIR, 'style.css');
|
|
27
|
-
fs.writeFileSync(cssFile, '.foo { color: red; }');
|
|
28
|
-
|
|
29
|
-
const plugin = new PostCssProcessorPlugin({
|
|
30
|
-
options: {
|
|
31
|
-
filter: /\.css$/,
|
|
32
|
-
transformInput: async (content) => {
|
|
33
|
-
return `/* prefix */\n${content}`;
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const config = await new ConfigBuilder()
|
|
39
|
-
.setRootDir(TMP_DIR)
|
|
40
|
-
.setSrcDir('src')
|
|
41
|
-
.setDistDir('dist')
|
|
42
|
-
.setBaseUrl('http://localhost:3000')
|
|
43
|
-
.build();
|
|
44
|
-
|
|
45
|
-
plugin.setContext(config);
|
|
46
|
-
|
|
47
|
-
const Bridge = {
|
|
48
|
-
cssUpdate: () => {},
|
|
49
|
-
error: (msg: string) => {
|
|
50
|
-
throw new Error(msg);
|
|
51
|
-
},
|
|
52
|
-
reload: () => {},
|
|
53
|
-
} as unknown as ClientBridge;
|
|
54
|
-
|
|
55
|
-
const bridgeSpy = vi.spyOn(Bridge, 'cssUpdate');
|
|
56
|
-
|
|
57
|
-
const watchConfig = plugin.getWatchConfig();
|
|
58
|
-
if (watchConfig && watchConfig.onChange) {
|
|
59
|
-
await watchConfig.onChange({ path: cssFile, bridge: Bridge });
|
|
60
|
-
} else {
|
|
61
|
-
throw new Error('Plugin does not have watch handler');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const outputFile = path.join(DIST_DIR, 'assets', 'style.css');
|
|
65
|
-
expect(fs.existsSync(outputFile)).toBe(true);
|
|
66
|
-
|
|
67
|
-
const outputContent = fs.readFileSync(outputFile, 'utf-8');
|
|
68
|
-
expect(outputContent).toContain('/* prefix */');
|
|
69
|
-
expect(outputContent).toContain('.foo { color: red; }');
|
|
70
|
-
|
|
71
|
-
expect(bridgeSpy).toHaveBeenCalled();
|
|
72
|
-
expect(bridgeSpy).toHaveBeenCalledWith(cssFile);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import postCssSimpleVars from 'postcss-simple-vars';
|
|
4
|
-
import { PostCssProcessor } from '../postcss-processor';
|
|
5
|
-
import { tailwindV3Preset } from '../presets/tailwind-v3';
|
|
6
|
-
|
|
7
|
-
describe('PostCssProcessor', () => {
|
|
8
|
-
test('processPath should return the processed CSS', async () => {
|
|
9
|
-
const filePath = path.resolve(__dirname, './css/correct.css');
|
|
10
|
-
const expected = '.test{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}';
|
|
11
|
-
const { plugins } = tailwindV3Preset();
|
|
12
|
-
const result = await PostCssProcessor.processPath(filePath, { plugins: plugins ? Object.values(plugins) : [] });
|
|
13
|
-
expect(result).toEqual(expected);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
test('processPath should return an empty string when an error occurs during css conversion', async () => {
|
|
17
|
-
const filePath = path.resolve(__dirname, './css/error.css');
|
|
18
|
-
const expected = '';
|
|
19
|
-
const { plugins } = tailwindV3Preset();
|
|
20
|
-
const result = await PostCssProcessor.processPath(filePath, { plugins: plugins ? Object.values(plugins) : [] });
|
|
21
|
-
expect(result).toEqual(expected);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('processPath should throw when the file does not exist', async () => {
|
|
25
|
-
const filePath = 'fake-path.css';
|
|
26
|
-
await expect(PostCssProcessor.processPath(filePath)).rejects.toThrow();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('processPath should use the custom plugins', async () => {
|
|
30
|
-
const filePath = path.resolve(__dirname, './css/external-plugins.css');
|
|
31
|
-
const expected = '.menu_link{background:#056ef0;width:200px}.menu{margin-top:10px;width:800px}';
|
|
32
|
-
const result = await PostCssProcessor.processPath(filePath, {
|
|
33
|
-
plugins: [...Object.values(tailwindV3Preset().plugins ?? {}), postCssSimpleVars()],
|
|
34
|
-
});
|
|
35
|
-
expect(result).toEqual(expected);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('processStringOrBuffer should return the processed CSS', async () => {
|
|
39
|
-
const string = 'body { @apply bg-white; }';
|
|
40
|
-
const expected = 'body{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}';
|
|
41
|
-
const { plugins } = tailwindV3Preset();
|
|
42
|
-
const result = await PostCssProcessor.processStringOrBuffer(string, {
|
|
43
|
-
plugins: plugins ? Object.values(plugins) : [],
|
|
44
|
-
});
|
|
45
|
-
expect(result).toEqual(expected);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('processStringOrBuffer should return an empty string when an error occurs during css conversion', async () => {
|
|
49
|
-
const string = 'body { @apply bg-whites; }';
|
|
50
|
-
const expected = '';
|
|
51
|
-
const { plugins } = tailwindV3Preset();
|
|
52
|
-
const result = await PostCssProcessor.processStringOrBuffer(string, {
|
|
53
|
-
plugins: plugins ? Object.values(plugins) : [],
|
|
54
|
-
});
|
|
55
|
-
expect(result).toEqual(expected);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('processStringOrBuffer should return an empty string when the input is empty', async () => {
|
|
59
|
-
const string = '';
|
|
60
|
-
const expected = '';
|
|
61
|
-
const result = await PostCssProcessor.processStringOrBuffer(string);
|
|
62
|
-
expect(result).toEqual(expected);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('processStringOrBuffer should use the custom plugins', async () => {
|
|
66
|
-
const string = '$blue: #056ef0; body { background: $blue; }';
|
|
67
|
-
const expected = 'body{background:#056ef0}';
|
|
68
|
-
const result = await PostCssProcessor.processStringOrBuffer(string, {
|
|
69
|
-
plugins: [...Object.values(tailwindV3Preset().plugins ?? {}), postCssSimpleVars()],
|
|
70
|
-
});
|
|
71
|
-
expect(result).toEqual(expected);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('processStringOrBuffer should use the transformOutput', async () => {
|
|
75
|
-
const string = 'body { background: #056ef0; }';
|
|
76
|
-
const expected = '@reference "../app.css";\nbody{background:#056ef0}';
|
|
77
|
-
const { plugins } = tailwindV3Preset();
|
|
78
|
-
const result = await PostCssProcessor.processStringOrBuffer(string, {
|
|
79
|
-
plugins: plugins?.cssnano ? [plugins.cssnano] : [],
|
|
80
|
-
transformOutput: (css) => {
|
|
81
|
-
return `@reference "../app.css";\n${css}`;
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
expect(result).toEqual(expected);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('processPath should resolve @import', async () => {
|
|
88
|
-
const filePath = path.resolve(__dirname, './css/import.css');
|
|
89
|
-
const expected = '.base{color:red}.main{background:blue}';
|
|
90
|
-
const { plugins } = tailwindV3Preset();
|
|
91
|
-
const result = await PostCssProcessor.processPath(filePath, { plugins: plugins ? Object.values(plugins) : [] });
|
|
92
|
-
expect(result).toEqual(expected);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test('processStringOrBuffer should resolve @import', async () => {
|
|
96
|
-
const string = '@import "base.css"; .main { background: blue; }';
|
|
97
|
-
const filePath = path.resolve(__dirname, './css/import.css');
|
|
98
|
-
const expected = '.base{color:red}.main{background:blue}';
|
|
99
|
-
const { plugins } = tailwindV3Preset();
|
|
100
|
-
const result = await PostCssProcessor.processStringOrBuffer(string, {
|
|
101
|
-
filePath,
|
|
102
|
-
plugins: plugins ? Object.values(plugins) : [],
|
|
103
|
-
});
|
|
104
|
-
expect(result).toEqual(expected);
|
|
105
|
-
});
|
|
106
|
-
});
|
package/src/test/presets.test.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { PostCssProcessor } from '../postcss-processor';
|
|
4
|
-
import { tailwindV3Preset } from '../presets/tailwind-v3';
|
|
5
|
-
import { tailwindV4Preset } from '../presets/tailwind-v4';
|
|
6
|
-
|
|
7
|
-
describe('Presets Verification', () => {
|
|
8
|
-
const cssToPrefix = `
|
|
9
|
-
.test-prefix {
|
|
10
|
-
user-select: none;
|
|
11
|
-
backdrop-filter: blur(10px);
|
|
12
|
-
appearance: none;
|
|
13
|
-
}
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
const cssWithImport = `
|
|
17
|
-
@import "base.css";
|
|
18
|
-
.main { background: blue; }
|
|
19
|
-
`;
|
|
20
|
-
|
|
21
|
-
test('Tailwind v3 preset should add vendor prefixes', async () => {
|
|
22
|
-
const { plugins } = tailwindV3Preset();
|
|
23
|
-
/**
|
|
24
|
-
* Disable cssnano for readable output logic check, or just check content calls
|
|
25
|
-
* By default preset includes cssnano.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
const result = await PostCssProcessor.processStringOrBuffer(cssToPrefix, {
|
|
29
|
-
plugins: plugins ? Object.values(plugins) : [],
|
|
30
|
-
filePath: path.resolve(__dirname, 'style.css'),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* cssnano will minify, so we check minified output
|
|
35
|
-
* user-select: none -> -webkit-user-select:none;user-select:none
|
|
36
|
-
* backdrop-filter: blur(10px) -> -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)
|
|
37
|
-
* appearance: none -> -webkit-appearance:none;-moz-appearance:none;appearance:none
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
expect(result).toContain('-webkit-user-select:none');
|
|
41
|
-
expect(result).toContain('user-select:none');
|
|
42
|
-
|
|
43
|
-
expect(result).toContain('-webkit-backdrop-filter:blur(10px)');
|
|
44
|
-
expect(result).toContain('backdrop-filter:blur(10px)');
|
|
45
|
-
|
|
46
|
-
expect(result).toContain('appearance:none');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('Tailwind v3 preset should support nesting', async () => {
|
|
50
|
-
const { plugins } = tailwindV3Preset();
|
|
51
|
-
const cssWithNesting = `
|
|
52
|
-
.parent {
|
|
53
|
-
& .child { color: blue; }
|
|
54
|
-
&__element { color: green; }
|
|
55
|
-
}
|
|
56
|
-
`;
|
|
57
|
-
|
|
58
|
-
const result = await PostCssProcessor.processStringOrBuffer(cssWithNesting, {
|
|
59
|
-
plugins: plugins ? Object.values(plugins) : [],
|
|
60
|
-
filePath: path.resolve(__dirname, 'style.css'),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(result).toContain('.parent .child{color:blue}');
|
|
64
|
-
expect(result).toContain('.parent__element{color:green}');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('Tailwind v4 preset should add vendor prefixes (via Lightning CSS)', async () => {
|
|
68
|
-
const preset = tailwindV4Preset({
|
|
69
|
-
referencePath: path.resolve(__dirname, '../fixtures/tailwind.css'),
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const result = await PostCssProcessor.processStringOrBuffer(cssToPrefix, {
|
|
73
|
-
plugins: preset.plugins ? Object.values(preset.plugins) : [],
|
|
74
|
-
filePath: path.resolve(__dirname, 'style.css'),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Lightning CSS used by @tailwindcss/postcss should verify this
|
|
79
|
-
* Note: The specific prefixes might depend on the browser targets configured in package.json or defaults
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
expect(result).toContain('-webkit-user-select:none');
|
|
83
|
-
expect(result).toContain('user-select:none');
|
|
84
|
-
|
|
85
|
-
expect(result).toContain('-webkit-backdrop-filter:blur(10px)');
|
|
86
|
-
expect(result).toContain('backdrop-filter:blur(10px)');
|
|
87
|
-
|
|
88
|
-
expect(result).toContain('appearance:none');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('Tailwind v4 preset should resolve @import', async () => {
|
|
92
|
-
const preset = tailwindV4Preset({
|
|
93
|
-
referencePath: path.resolve(__dirname, '../fixtures/tailwind.css'),
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Provide a filePath that allows resolving sibling files (like base.css in existing tests/css dir)
|
|
98
|
-
* We'll leverage the existing test css files
|
|
99
|
-
*/
|
|
100
|
-
const filePath = path.resolve(__dirname, 'css/import.css');
|
|
101
|
-
|
|
102
|
-
const result = await PostCssProcessor.processStringOrBuffer(cssWithImport, {
|
|
103
|
-
plugins: preset.plugins ? Object.values(preset.plugins) : [],
|
|
104
|
-
filePath,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Expect content from base.css (.base { color: red }) + main css content
|
|
109
|
-
* Minified output expected
|
|
110
|
-
*/
|
|
111
|
-
expect(result).toContain('.base{color:red}');
|
|
112
|
-
expect(result).toContain('.main{background:blue}');
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('Tailwind v4 preset should support nesting', async () => {
|
|
117
|
-
const preset = tailwindV4Preset({
|
|
118
|
-
referencePath: path.resolve(__dirname, '../fixtures/tailwind.css'),
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
const cssWithNesting = `
|
|
122
|
-
.parent {
|
|
123
|
-
color: red;
|
|
124
|
-
& .child {
|
|
125
|
-
color: blue;
|
|
126
|
-
}
|
|
127
|
-
&__element {
|
|
128
|
-
color: green;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
`;
|
|
132
|
-
|
|
133
|
-
const result = await PostCssProcessor.processStringOrBuffer(cssWithNesting, {
|
|
134
|
-
plugins: preset.plugins ? Object.values(preset.plugins) : [],
|
|
135
|
-
filePath: path.resolve(__dirname, 'style.css'),
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
expect(result).toContain('.parent .child{color:blue}');
|
|
139
|
-
expect(result).toContain('.parent__element{color:green}');
|
|
140
|
-
});
|