Skip to content

Commit

Permalink
postcss-bundler : do not shift up @import statements (#1161)
Browse files Browse the repository at this point in the history
  • Loading branch information
romainmenke authored Oct 31, 2023
1 parent 2bd92ea commit d17488a
Show file tree
Hide file tree
Showing 157 changed files with 1,070 additions and 567 deletions.
17 changes: 7 additions & 10 deletions plugin-packs/postcss-bundler/.tape.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const testCases = {
},
'ignore': {
message: "ignores incorrect syntax",
warnings: 3,
warnings: 4,
},
'regexp': {
message: "regexp sanity checks",
Expand All @@ -45,28 +45,25 @@ const testCases = {
}

switch (dirent.path.split(path.sep).join(path.posix.sep)) {
case 'test/css-import-tests/003-should-fail/001-core-features/before-other-styles/002':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/002-sub-features/004-at-supports/007':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/002-sub-features/003-at-layer/011':
case 'test/css-import-tests/002-sub-features/001-data-urls/004':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/002-sub-features/001-data-urls/004':
case 'test/css-import-tests/001-core-features/url-fragments/004':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/001-core-features/namespace/002':
case 'test/css-import-tests/001-core-features/url-fragments/005':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/001-core-features/before-other-styles/001':
case 'test/css-import-tests/001-core-features/forwards-compat/004':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/001-core-features/before-other-styles/002':
case 'test/css-import-tests/002-sub-features/003-at-layer/013':
testCases[key].warnings = 1;
break;
case 'test/css-import-tests/001-core-features/url-fragments/004':
case 'test/css-import-tests/002-sub-features/004-at-supports/012':
testCases[key].warnings = 1;
break;
default:
Expand Down
4 changes: 4 additions & 0 deletions plugin-packs/postcss-bundler/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes to PostCSS Bundler

### Unreleased (patch)

- Fix layer statements that precede `@import` statements which link to external resources

### 1.0.6

_October 5, 2023_
Expand Down
2 changes: 1 addition & 1 deletion plugin-packs/postcss-bundler/dist/index.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion plugin-packs/postcss-bundler/dist/index.mjs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { AtRule, AtRuleProps } from 'postcss';
import { Statement } from './statement';
export declare function applyConditions(bundle: Array<Statement>, atRule: (defaults?: AtRuleProps) => AtRule): void;
import { Stylesheet } from './statement';
export declare function applyConditions(stylesheet: Stylesheet, atRule: (defaults?: AtRuleProps) => AtRule): void;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { Document, Root } from 'postcss';
import { Statement } from './statement';
export declare function applyStyles(bundle: Array<Statement>, styles: Root | Document): void;
import { Stylesheet } from './statement';
export declare function applyStyles(stylesheet: Stylesheet, styles: Root | Document): void;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { Condition } from './conditions';
export declare function base64EncodedConditionalImport(prelude: string, conditions: Array<Condition>): string;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Document, Postcss, Result, Root, AtRule } from 'postcss';
import { Statement } from './statement';
import { Stylesheet } from './statement';
import { Condition } from './conditions';
export declare function parseStyles(result: Result, styles: Root | Document, importingNode: AtRule | null, conditions: Array<Condition>, from: Array<string>, postcss: Postcss): Promise<Statement[]>;
export declare function parseStyles(result: Result, styles: Root | Document, importingNode: AtRule | null, conditions: Array<Condition>, from: Array<string>, postcss: Postcss): Promise<Stylesheet>;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AtRule, Document, Result, Root } from 'postcss';
import { Condition } from './conditions';
import { Statement } from './statement';
export declare function parseStatements(result: Result, styles: Root | Document, importingNode: AtRule | null, conditions: Array<Condition>, from: Array<string>): Array<Statement>;
import { Stylesheet } from './statement';
export declare function parseStylesheet(result: Result, styles: Root | Document, importingNode: AtRule | null, conditions: Array<Condition>, from: Array<string>): Stylesheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { AtRule, AtRuleProps } from 'postcss';
import { Stylesheet } from './statement';
export declare function postProcess(stylesheet: Stylesheet, atRule: (defaults?: AtRuleProps) => AtRule): void;
26 changes: 15 additions & 11 deletions plugin-packs/postcss-bundler/dist/postcss-import/lib/statement.d.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
import type { AtRule, ChildNode, Warning } from 'postcss';
import { Condition } from './conditions';
export type Statement = ImportStatement | CharsetStatement | NodesStatement | Warning;
export type Stylesheet = {
charset?: AtRule;
statements: Array<Statement>;
};
export type Statement = ImportStatement | PreImportStatement | NodesStatement | Warning;
export type NodesStatement = {
type: string;
type: 'nodes';
nodes: Array<ChildNode>;
conditions: Array<Condition>;
from: Array<string>;
parent?: Statement;
importingNode: AtRule | null;
};
export type CharsetStatement = {
type: string;
export type ImportStatement = {
type: 'import';
uri: string;
fullUri: string;
node: AtRule;
conditions: Array<Condition>;
from: Array<string>;
parent?: Statement;
stylesheet?: Stylesheet;
importingNode: AtRule | null;
};
export type ImportStatement = {
type: string;
uri: string;
fullUri: string;
node: AtRule;
export type PreImportStatement = {
type: 'pre-import';
node: ChildNode;
conditions: Array<Condition>;
from: Array<string>;
parent?: Statement;
children?: Array<Statement>;
importingNode: AtRule | null;
};
export declare function isWarning(stmt: Statement): stmt is Warning;
export declare function isNodesStatement(stmt: Statement): stmt is NodesStatement;
export declare function isCharsetStatement(stmt: Statement): stmt is CharsetStatement;
export declare function isImportStatement(stmt: Statement): stmt is ImportStatement;
export declare function isPreImportStatement(stmt: Statement): stmt is PreImportStatement;
3 changes: 3 additions & 0 deletions plugin-packs/postcss-bundler/src/postcss-import/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { PluginCreator } from 'postcss';
import { parseStyles } from './lib/parse-styles';
import { applyConditions } from './lib/apply-conditions';
import { applyStyles } from './lib/apply-styles';
import { postProcess } from './lib/post-process';

/** postcss-bundler plugin options */
export type pluginOptions = never;
Expand All @@ -19,6 +20,8 @@ const creator: PluginCreator<pluginOptions> = () => {
postcss,
);

postProcess(bundle, atRule);

applyConditions(bundle, atRule);
applyStyles(bundle, styles);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
import type { AtRule, AtRuleProps } from 'postcss';
import { Statement, isCharsetStatement, isImportStatement, isWarning } from './statement';
import { formatImportPrelude } from './format-import-prelude';
import { Stylesheet, isImportStatement, isPreImportStatement, isWarning } from './statement';
import { base64EncodedConditionalImport } from './base64-encoded-import';

export function applyConditions(bundle: Array<Statement>, atRule: (defaults?: AtRuleProps) => AtRule) {
bundle.forEach((stmt, index) => {
if (isWarning(stmt) || isCharsetStatement(stmt) || !stmt.conditions?.length) {
export function applyConditions(stylesheet: Stylesheet, atRule: (defaults?: AtRuleProps) => AtRule) {
stylesheet.statements.forEach((stmt, index) => {
if (isWarning(stmt) || isPreImportStatement(stmt) || !stmt.conditions?.length) {
return;
}

if (isImportStatement(stmt)) {
stmt.conditions.reverse();
const first = stmt.conditions.pop()!;
let params = `${stmt.fullUri} ${formatImportPrelude(
first.layer,
first.media,
first.supports,
)}`;

for (const condition of stmt.conditions) {
params = `'data:text/css;base64,${Buffer.from(
`@import ${params}`,
).toString('base64')}' ${formatImportPrelude(
condition.layer,
condition.media,
condition.supports,
)}`;
}

stmt.node.params = params;

stmt.node.params = base64EncodedConditionalImport(stmt.fullUri, stmt.conditions);
return;
}

Expand Down Expand Up @@ -98,7 +79,7 @@ export function applyConditions(bundle: Array<Statement>, atRule: (defaults?: At
// wrap new rules with media query and/or layer at rule
innerAtRule.append(nodes);

bundle[index] = {
stylesheet.statements[index] = {
type: 'nodes',
nodes: [outerAtRule],
conditions: stmt.conditions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import type { Document, Root } from 'postcss';
import { Statement, isCharsetStatement, isImportStatement } from './statement';
import { Stylesheet, isImportStatement, isNodesStatement } from './statement';

export function applyStyles(bundle: Array<Statement>, styles: Root | Document) {
export function applyStyles(stylesheet: Stylesheet, styles: Root | Document) {
styles.nodes = [];

if (stylesheet.charset) {
stylesheet.charset.parent = undefined;
styles.append(stylesheet.charset);
}

// Strip additional statements.
bundle.forEach(stmt => {
if (isCharsetStatement(stmt) || isImportStatement(stmt)) {
stylesheet.statements.forEach((stmt) => {
if (isImportStatement(stmt)) {
stmt.node.parent = undefined;
styles.append(stmt.node);
} else if (stmt.type === 'nodes') {
stmt.nodes.forEach(node => {
} else if (isNodesStatement(stmt)) {
stmt.nodes.forEach((node) => {
node.parent = undefined;
styles.append(node);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Condition } from './conditions';
import { formatImportPrelude } from './format-import-prelude';

// Base64 encode an import with conditions
// The order of conditions is important and is interleaved with cascade layer declarations
// Each group of conditions and cascade layers needs to be interpreted in order
// To achieve this we create a list of base64 encoded imports, where each import contains a stylesheet with another import.
// Each import can define a single group of conditions and a single cascade layer.
export function base64EncodedConditionalImport(prelude: string, conditions: Array<Condition>): string {
conditions.reverse();
const first = conditions.pop()!;
let params = `${prelude} ${formatImportPrelude(
first.layer,
first.media,
first.supports,
)}`;

for (const condition of conditions) {
params = `'data:text/css;base64,${Buffer.from(
`@import ${params}`,
).toString('base64')}' ${formatImportPrelude(
condition.layer,
condition.media,
condition.supports,
)}`;
}

return params;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function parseAtImport(params: string) : false | { uri: string; fullUri:
}

if (
!uri &&
isTokenNode(childComponentValue) &&
childComponentValue.value[0] === TokenType.String
) {
Expand Down
Loading

0 comments on commit d17488a

Please sign in to comment.