-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@angular-devkit/build-angular): support using custom postcss con…
…figuration with application builder When using the `application` builder, the usage of a custom postcss configuration is now supported. The builder will automatically detect and use specific postcss configuration files if present in either the project root directory or the workspace root. Files present in the project root will have priority over a workspace root file. If using a custom postcss configuration file, the automatic tailwind integration will be disabled. To use both a custom postcss configuration and tailwind, the tailwind setup must be included in the custom postcss configuration file. The configuration files must be JSON and named one of the following: * `postcss.config.json` * `.postcssrc.json` A configuration file can use either an array form or an object form to setup plugins. An example of the array form: ``` { "plugins": [ "tailwindcss", ["rtlcss", { "useCalc": true }] ] } ``` The same in an object form: ``` { "plugins": { "tailwindcss": {}, "rtlcss": { "useCalc": true } } } ``` NOTE: Using a custom postcss configuration may result in reduced build and rebuild performance. Postcss will be used to process all global and component stylesheets when a custom configuration is present. Without a custom postcss configuration, postcss is only used for a stylesheet when tailwind is enabled and the stylesheet requires tailwind processing.
- Loading branch information
1 parent
944cbcd
commit 7c522aa
Showing
6 changed files
with
168 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
packages/angular_devkit/build_angular/src/utils/postcss-configuration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/** | ||
* @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 { readFile, readdir } from 'node:fs/promises'; | ||
import { join } from 'node:path'; | ||
|
||
export interface PostcssConfiguration { | ||
plugins: [name: string, options?: object][]; | ||
} | ||
|
||
interface RawPostcssConfiguration { | ||
plugins?: Record<string, object | boolean> | (string | [string, object])[]; | ||
} | ||
|
||
const postcssConfigurationFiles: string[] = ['postcss.config.json', '.postcssrc.json']; | ||
|
||
interface SearchDirectory { | ||
root: string; | ||
files: Set<string>; | ||
} | ||
|
||
async function generateSearchDirectories(roots: string[]): Promise<SearchDirectory[]> { | ||
return await Promise.all( | ||
roots.map((root) => | ||
readdir(root, { withFileTypes: true }).then((entries) => ({ | ||
root, | ||
files: new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name)), | ||
})), | ||
), | ||
); | ||
} | ||
|
||
function findFile( | ||
searchDirectories: SearchDirectory[], | ||
potentialFiles: string[], | ||
): string | undefined { | ||
for (const { root, files } of searchDirectories) { | ||
for (const potential of potentialFiles) { | ||
if (files.has(potential)) { | ||
return join(root, potential); | ||
} | ||
} | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
async function readPostcssConfiguration( | ||
configurationFile: string, | ||
): Promise<RawPostcssConfiguration> { | ||
const data = await readFile(configurationFile, 'utf-8'); | ||
const config = JSON.parse(data) as RawPostcssConfiguration; | ||
|
||
return config; | ||
} | ||
|
||
export async function loadPostcssConfiguration( | ||
workspaceRoot: string, | ||
projectRoot: string, | ||
): Promise<PostcssConfiguration | undefined> { | ||
// A configuration file can exist in the project or workspace root | ||
const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]); | ||
|
||
const configPath = findFile(searchDirectories, postcssConfigurationFiles); | ||
if (!configPath) { | ||
return undefined; | ||
} | ||
|
||
const raw = await readPostcssConfiguration(configPath); | ||
|
||
// If no plugins are defined, consider it equivalent to no configuration | ||
if (!raw.plugins || typeof raw.plugins !== 'object') { | ||
return undefined; | ||
} | ||
|
||
// Normalize plugin array form | ||
if (Array.isArray(raw.plugins)) { | ||
if (raw.plugins.length < 1) { | ||
return undefined; | ||
} | ||
|
||
const config: PostcssConfiguration = { plugins: [] }; | ||
for (const element of raw.plugins) { | ||
if (typeof element === 'string') { | ||
config.plugins.push([element]); | ||
} else { | ||
config.plugins.push(element); | ||
} | ||
} | ||
|
||
return config; | ||
} | ||
|
||
// Normalize plugin object map form | ||
const entries = Object.entries(raw.plugins); | ||
if (entries.length < 1) { | ||
return undefined; | ||
} | ||
|
||
const config: PostcssConfiguration = { plugins: [] }; | ||
for (const [name, options] of entries) { | ||
if (!options || typeof options !== 'object') { | ||
continue; | ||
} | ||
|
||
config.plugins.push([name, options]); | ||
} | ||
|
||
return config; | ||
} |