Skip to content

Commit c149378

Browse files
committed
feat(@angular-devkit/build-angular): tailwindcss purge
1 parent b105ed6 commit c149378

File tree

2 files changed

+84
-10
lines changed
  • packages/angular_devkit/build_angular/src/webpack/configs
  • tests/legacy-cli/e2e/tests/build/styles

2 files changed

+84
-10
lines changed

packages/angular_devkit/build_angular/src/webpack/configs/styles.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,27 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
186186
);
187187
}
188188
if (tailwindPackagePath) {
189-
extraPostcssPlugins.push(require(tailwindPackagePath)({ config: tailwindConfigPath }));
189+
const tailwindConfig = require(tailwindConfigPath);
190+
if (typeof tailwindConfig !== 'function') {
191+
if (!tailwindConfig.purge) {
192+
tailwindConfig.purge = {};
193+
}
194+
if (Array.isArray(tailwindConfig.purge)) {
195+
tailwindConfig.purge = {
196+
content: [...tailwindConfig.purge],
197+
};
198+
}
199+
if (typeof tailwindConfig.purge.enabled === 'undefined') {
200+
tailwindConfig.purge.enabled = !!buildOptions.optimization?.styles.minify;
201+
}
202+
203+
} else {
204+
wco.logger.warn(
205+
`Tailwind CSS configuration file export function instead of object.` +
206+
` To enable Purge in Tailwind CSS, please make sure to export an object.`,
207+
);
208+
}
209+
extraPostcssPlugins.push(require(tailwindPackagePath)(tailwindConfig));
190210
}
191211
}
192212

tests/legacy-cli/e2e/tests/build/styles/tailwind.ts

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { deleteFile, expectFileToMatch, writeFile } from '../../../utils/fs';
1+
import { deleteFile, expectFileToMatch, replaceInFile, writeFile } from '../../../utils/fs';
22
import { installPackage, uninstallPackage } from '../../../utils/packages';
33
import { ng, silentExec } from '../../../utils/process';
4+
import { updateJsonFile } from '../../../utils/project';
45
import { expectToFail } from '../../../utils/utils';
56

67
export default async function () {
@@ -14,12 +15,18 @@ export default async function () {
1415

1516
// Create configuration file
1617
await silentExec('npx', 'tailwindcss', 'init');
18+
await replaceInFile('tailwind.config.js', `purge: [],`, `purge: ['./src/**/*.{html,ts}'],`);
19+
await updateJsonFile('angular.json', json => {
20+
json.projects['test-project'].architect.build.configurations.production.budgets = [
21+
{ type: 'all', maximumError: '100mb' },
22+
];
23+
});
1724

1825
// Add Tailwind directives to a component style
19-
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components;');
26+
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components; @tailwind utilities');
2027

2128
// Add Tailwind directives to a global style
22-
await writeFile('src/styles.css', '@tailwind base; @tailwind components;');
29+
await writeFile('src/styles.css', '@tailwind base; @tailwind components; @tailwind utilities');
2330

2431
// Build should succeed and process Tailwind directives
2532
await ng('build');
@@ -28,19 +35,66 @@ export default async function () {
2835
await expectFileToMatch('dist/test-project/styles.css', /::placeholder/);
2936
await expectFileToMatch('dist/test-project/main.js', /::placeholder/);
3037
await expectToFail(() =>
31-
expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components;'),
38+
expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components; @tailwind utilities'),
3239
);
3340
await expectToFail(() =>
34-
expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components;'),
41+
expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components; @tailwind utilities'),
3542
);
3643

44+
45+
await writeFile('src/app/app.component.html', '<div class="py-2 px-4 rounded-md bg-red-400">Test</div>');
46+
await ng('build', '--prod', '--output-hashing=none');
47+
await expectFileToMatch('dist/test-project/styles.css', /\.rounded-md/);
48+
await expectFileToMatch('dist/test-project/main.js', /\.rounded-md/);
49+
await expectToFail(() =>
50+
expectFileToMatch('dist/test-project/styles.css', /\.py-3/),
51+
);
52+
await expectToFail(() =>
53+
expectFileToMatch('dist/test-project/main.js', /\.py-3/),
54+
);
55+
await replaceInFile('tailwind.config.js', `purge: ['./src/**/*.{html,ts}'],`, `purge: {
56+
content: [
57+
'./src/**/*.{html,ts}',
58+
]
59+
},`);
60+
await ng('build', '--prod', '--output-hashing=none');
61+
await expectFileToMatch('dist/test-project/styles.css', /\.rounded-md/);
62+
await expectFileToMatch('dist/test-project/main.js', /\.rounded-md/);
63+
await expectToFail(() =>
64+
expectFileToMatch('dist/test-project/styles.css', /\.py-3/),
65+
);
66+
await expectToFail(() =>
67+
expectFileToMatch('dist/test-project/main.js', /\.py-3/),
68+
);
69+
70+
await replaceInFile('tailwind.config.js', `purge: {`, `purge: { enabled: false,`);
71+
await ng('build', '--prod', '--output-hashing=none');
72+
expectFileToMatch('dist/test-project/styles.css', /\.py-3/),
73+
expectFileToMatch('dist/test-project/main.js', /\.py-3/),
74+
await replaceInFile('tailwind.config.js', `purge: { enabled: false,`, `purge: { enabled: true,`);
75+
await ng('build');
76+
await expectToFail(() =>
77+
expectFileToMatch('dist/test-project/styles.css', /\.py-3/),
78+
);
79+
await expectToFail(() =>
80+
expectFileToMatch('dist/test-project/main.js', /\.py-3/),
81+
);
82+
83+
84+
await writeFile('tailwind.config.js', 'module.exports = () => {}');
85+
const { stderr: _err } = await ng('build');
86+
if (!_err.includes("file export function instead of object")) {
87+
throw new Error('Expected tailwind config error');
88+
}
89+
90+
3791
// Remove configuration file
3892
await deleteFile('tailwind.config.js');
3993

4094
// Ensure Tailwind is disabled when no configuration file is present
4195
await ng('build');
42-
await expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components;');
43-
await expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components;');
96+
await expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components; @tailwind utilities');
97+
await expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components; @tailwind utilities');
4498

4599
// Recreate configuration file
46100
await silentExec('npx', 'tailwindcss', 'init');
@@ -55,6 +109,6 @@ export default async function () {
55109
}
56110

57111
// Tailwind directives should be unprocessed with missing package
58-
await expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components;');
59-
await expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components;');
112+
await expectFileToMatch('dist/test-project/styles.css', '@tailwind base; @tailwind components; @tailwind utilities');
113+
await expectFileToMatch('dist/test-project/main.js', '@tailwind base; @tailwind components; @tailwind utilities');
60114
}

0 commit comments

Comments
 (0)