Skip to content

Commit 18e5dc6

Browse files
MeAkibalan-agius4
authored andcommitted
fix(@schematics/angular): ignore non-workspace stylesheet entries when adding Tailwind
The tailwind schematic selects the first `styles` entry ending in `.css` and appends the Tailwind import to it without checking that the entry is a file in the workspace. When the first `.css` entry is a package specifier such as `@angular/material/prebuilt-themes/azure-blue.css`, `ng add tailwindcss` fails with a file-does-not-exist exception, and when it is a path within `node_modules`, the vendor stylesheet is modified instead of a project file. Only consider entries that exist in the workspace and are not within `node_modules`, falling back to creating a dedicated `tailwind.css` otherwise. New specs reproduce both failures without this change. (cherry picked from commit a68d0df)
1 parent eaf2343 commit 18e5dc6

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

‎packages/schematics/angular/tailwind/index.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ function addTailwindStyles(options: { project: string }, project: ProjectDefinit
4848

4949
let stylesheetPath: string | undefined;
5050
if (styles) {
51+
// Only consider workspace source files. Entries such as package specifiers
52+
// (`@angular/material/prebuilt-themes/...`) or files within `node_modules` must not be modified.
5153
stylesheetPath = styles
5254
.map((s) => (typeof s === 'string' ? s : s.input))
53-
.find((p) => p.endsWith('.css'));
55+
.find((p) => p.endsWith('.css') && !/(?:^|\/)node_modules\//.test(p) && tree.exists(p));
5456
}
5557

5658
if (!stylesheetPath) {

‎packages/schematics/angular/tailwind/index_spec.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,40 @@ describe('Tailwind Schematic', () => {
129129
expect(tree.exists('/projects/bar/.postcssrc.json')).toBe(false);
130130
});
131131
});
132+
133+
describe('with non-workspace stylesheets', () => {
134+
function setStyles(tree: UnitTestTree, styles: string[]): void {
135+
const workspace = getWorkspace(tree);
136+
workspace.projects.bar.architect.build.options.styles = styles;
137+
tree.overwrite('/angular.json', JSON.stringify(workspace, null, 2));
138+
}
139+
140+
it('should create a tailwind stylesheet when the only CSS entry is a package theme', async () => {
141+
setStyles(appTree, [
142+
'@angular/material/prebuilt-themes/azure-blue.css',
143+
'projects/bar/src/styles.scss',
144+
]);
145+
146+
const tree = await schematicRunner.runSchematic('tailwind', { project: 'bar' }, appTree);
147+
148+
expect(tree.exists('/projects/bar/src/tailwind.css')).toBe(true);
149+
const workspace = getWorkspace(tree);
150+
expect(workspace.projects.bar.architect.build.options.styles).toEqual([
151+
'projects/bar/src/tailwind.css',
152+
'@angular/material/prebuilt-themes/azure-blue.css',
153+
'projects/bar/src/styles.scss',
154+
]);
155+
});
156+
157+
it('should not modify a stylesheet inside node_modules', async () => {
158+
const vendorStylesheet = 'node_modules/bootstrap/dist/css/bootstrap.min.css';
159+
appTree.create(`/${vendorStylesheet}`, 'body { margin: 0; }');
160+
setStyles(appTree, [vendorStylesheet, 'projects/bar/src/styles.css']);
161+
162+
const tree = await schematicRunner.runSchematic('tailwind', { project: 'bar' }, appTree);
163+
164+
expect(tree.readContent(`/${vendorStylesheet}`)).not.toContain('tailwindcss');
165+
expect(tree.readContent('/projects/bar/src/styles.css')).toContain(`@import 'tailwindcss';`);
166+
});
167+
});
132168
});

0 commit comments

Comments
 (0)