Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): update list of known tailwind con…
Browse files Browse the repository at this point in the history
…figuration files

With this change we added `tailwind.config.mjs` and `tailwind.config.ts` to known tailwind config files.

Closes #24943
  • Loading branch information
alan-agius4 authored and angular-robot[bot] committed Apr 18, 2023
1 parent d5fed32 commit 758b069
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import path from 'node:path';
import { normalizeAssetPatterns, normalizeOptimization, normalizeSourceMaps } from '../../utils';
import { normalizeCacheOptions } from '../../utils/normalize-cache';
import { generateEntryPoints } from '../../utils/package-chunk-sort';
import { findTailwindConfigurationFile } from '../../utils/tailwind';
import { getIndexInputFile, getIndexOutputFile } from '../../utils/webpack-browser-config';
import { globalScriptsByBundleName, normalizeGlobalStyles } from '../../webpack/utils/helpers';
import { Schema as BrowserBuilderOptions, OutputHashing } from './schema';
Expand Down Expand Up @@ -97,7 +98,7 @@ export async function normalizeOptions(
}

let tailwindConfiguration: { file: string; package: string } | undefined;
const tailwindConfigurationPath = findTailwindConfigurationFile(workspaceRoot, projectRoot);
const tailwindConfigurationPath = await findTailwindConfigurationFile(workspaceRoot, projectRoot);
if (tailwindConfigurationPath) {
// Create a node resolver at the project root as a directory
const resolver = createRequire(projectRoot + '/');
Expand Down Expand Up @@ -203,27 +204,6 @@ export async function normalizeOptions(
};
}

function findTailwindConfigurationFile(
workspaceRoot: string,
projectRoot: string,
): string | undefined {
// A configuration file can exist in the project or workspace root
// The list of valid config files can be found:
// https://github.com/tailwindlabs/tailwindcss/blob/8845d112fb62d79815b50b3bae80c317450b8b92/src/util/resolveConfigPath.js#L46-L52
const tailwindConfigFiles = ['tailwind.config.js', 'tailwind.config.cjs'];
for (const basePath of [projectRoot, workspaceRoot]) {
for (const configFile of tailwindConfigFiles) {
// Project level configuration should always take precedence.
const fullPath = path.join(basePath, configFile);
if (fs.existsSync(fullPath)) {
return fullPath;
}
}
}

return undefined;
}

/**
* Normalize a directory path string.
* Currently only removes a trailing slash if present.
Expand Down
40 changes: 40 additions & 0 deletions packages/angular_devkit/build_angular/src/utils/tailwind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import { readdir } from 'node:fs/promises';
import { join } from 'node:path';

const tailwindConfigFiles: string[] = [
'tailwind.config.js',
'tailwind.config.cjs',
'tailwind.config.mjs',
'tailwind.config.ts',
];

export async function findTailwindConfigurationFile(
workspaceRoot: string,
projectRoot: string,
): Promise<string | undefined> {
const dirEntries = [projectRoot, workspaceRoot].map((root) =>
readdir(root, { withFileTypes: false }).then((entries) => ({
root,
files: new Set(entries),
})),
);

// A configuration file can exist in the project or workspace root
for await (const { root, files } of dirEntries) {
for (const potentialConfig of tailwindConfigFiles) {
if (files.has(potentialConfig)) {
return join(root, potentialConfig);
}
}
}

return undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { pathToFileURL } from 'node:url';
import type { FileImporter } from 'sass';
Expand All @@ -19,6 +18,7 @@ import {
import { SassLegacyWorkerImplementation } from '../../sass/sass-service-legacy';
import { WebpackConfigOptions } from '../../utils/build-options';
import { useLegacySass } from '../../utils/environment-options';
import { findTailwindConfigurationFile } from '../../utils/tailwind';
import {
AnyComponentStyleBudgetChecker,
PostcssCliResources,
Expand All @@ -34,8 +34,8 @@ import {
} from '../utils/helpers';

// eslint-disable-next-line max-lines-per-function
export function getStylesConfig(wco: WebpackConfigOptions): Configuration {
const { root, buildOptions, logger } = wco;
export async function getStylesConfig(wco: WebpackConfigOptions): Promise<Configuration> {
const { root, buildOptions, logger, projectRoot } = wco;
const extraPlugins: Configuration['plugins'] = [];

extraPlugins.push(new AnyComponentStyleBudgetChecker(buildOptions.budgets));
Expand Down Expand Up @@ -86,13 +86,13 @@ export function getStylesConfig(wco: WebpackConfigOptions): Configuration {
// Only load Tailwind CSS plugin if configuration file was found.
// This acts as a guard to ensure the project actually wants to use Tailwind CSS.
// The package may be unknowningly present due to a third-party transitive package dependency.
const tailwindConfigPath = getTailwindConfigPath(wco);
const tailwindConfigPath = await findTailwindConfigurationFile(root, projectRoot);
if (tailwindConfigPath) {
let tailwindPackagePath;
try {
tailwindPackagePath = require.resolve('tailwindcss', { paths: [wco.root] });
tailwindPackagePath = require.resolve('tailwindcss', { paths: [root] });
} catch {
const relativeTailwindConfigPath = path.relative(wco.root, tailwindConfigPath);
const relativeTailwindConfigPath = path.relative(root, tailwindConfigPath);
logger.warn(
`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
` but the 'tailwindcss' package is not installed.` +
Expand Down Expand Up @@ -315,24 +315,6 @@ export function getStylesConfig(wco: WebpackConfigOptions): Configuration {
};
}

function getTailwindConfigPath({ projectRoot, root }: WebpackConfigOptions): string | undefined {
// A configuration file can exist in the project or workspace root
// The list of valid config files can be found:
// https://github.com/tailwindlabs/tailwindcss/blob/8845d112fb62d79815b50b3bae80c317450b8b92/src/util/resolveConfigPath.js#L46-L52
const tailwindConfigFiles = ['tailwind.config.js', 'tailwind.config.cjs'];
for (const basePath of [projectRoot, root]) {
for (const configFile of tailwindConfigFiles) {
// Irrespective of the name project level configuration should always take precedence.
const fullPath = path.join(basePath, configFile);
if (fs.existsSync(fullPath)) {
return fullPath;
}
}
}

return undefined;
}

function getSassLoaderOptions(
root: string,
implementation: SassWorkerImplementation | SassLegacyWorkerImplementation,
Expand Down Expand Up @@ -399,7 +381,7 @@ function getSassResolutionImporter(
root: string,
preserveSymlinks: boolean,
): FileImporter<'async'> {
const commonResolverOptions: Parameters<typeof loaderContext['getResolve']>[0] = {
const commonResolverOptions: Parameters<(typeof loaderContext)['getResolve']>[0] = {
conditionNames: ['sass', 'style'],
mainFields: ['sass', 'style', 'main', '...'],
extensions: ['.scss', '.sass', '.css'],
Expand Down

0 comments on commit 758b069

Please sign in to comment.