Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion openframe-frontend-core/scripts/route-styles.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ async function stylesheetBuilder({ root, input, config }) {
const postcss = require(require.resolve('postcss', { paths: [root, __dirname] }));
const loadConfig = require(require.resolve('tailwindcss/loadConfig', { paths: [root, __dirname] }));
const source = readInput(resolve(root, input), root);
const appConfig = loadConfig(resolve(root, config));
const { APP_TAILWIND_CONFIG } = require('./style-sources.cjs');
const loaded = loadConfig(resolve(root, config));
const appConfig = loaded[APP_TAILWIND_CONFIG] ?? loaded;
const minify = minifier(root);
const from = resolve(root, input);
return async content => {
Expand Down
17 changes: 15 additions & 2 deletions openframe-frontend-core/scripts/style-sources.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ if (require.main === module) {
);
}

/**
* The config `withRouteStylesTailwind` was given. The route step runs inside `next build`, under the same
* `NEXT_STYLES=routes`, so the config it loads is the wrapped one: the complete sheet is built from this.
*/
const APP_TAILWIND_CONFIG = Symbol.for('next-styles.app-tailwind-config');

/**
* The Tailwind config of the stylesheet the root layout imports, for `next-styles build`: under it that sheet is
* built with no utilities (its tokens, preflight and the app's own rules), because each route's utilities arrive
Expand All @@ -269,7 +275,14 @@ if (require.main === module) {
*/
function withRouteStylesTailwind(config) {
if (process.env.NEXT_STYLES !== 'routes') return config;
return { ...config, content: [{ raw: '', extension: 'html' }], safelist: [] };
return { ...config, content: [{ raw: '', extension: 'html' }], safelist: [], [APP_TAILWIND_CONFIG]: config };
}

module.exports = { appStyleSources, routePaths, servedRouteFiles, LAZY_STYLED, withRouteStylesTailwind };
module.exports = {
appStyleSources,
routePaths,
servedRouteFiles,
LAZY_STYLED,
withRouteStylesTailwind,
APP_TAILWIND_CONFIG,
};
3 changes: 3 additions & 0 deletions openframe-frontend-core/scripts/style-sources.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ export function appStyleSources(options: AppStyleSourcesOptions): string[];

/** The root sheet's Tailwind config: no utilities under `next-styles build` (each route brings its own). */
export function withRouteStylesTailwind<T extends object>(config: T): T;

/** Where a config wrapped by {@link withRouteStylesTailwind} keeps the app's own (the complete sheet's). */
export const APP_TAILWIND_CONFIG: unique symbol;
50 changes: 47 additions & 3 deletions openframe-frontend-core/src/__tests__/route-styles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ const { withRouteStyles, fullSheetUrl } = require('../../scripts/next-styles.cjs
withRouteStyles: (config: object) => (phase: string) => Promise<Record<string, unknown>>;
fullSheetUrl: (info: { buildId: string; assetPrefix?: string; basePath?: string }) => string;
};
const { withRouteStylesTailwind } = require('../../scripts/style-sources.cjs') as {
const { withRouteStylesTailwind, APP_TAILWIND_CONFIG } = require('../../scripts/style-sources.cjs') as {
withRouteStylesTailwind: <T extends object>(config: T) => T;
APP_TAILWIND_CONFIG: symbol;
};

describe('route-styles: the classes a page renders', () => {
Expand Down Expand Up @@ -115,6 +116,47 @@ describe('route-styles: a route sheet is the complete sheet with rules left out'
});
});

describe('route-styles: the complete sheet under next-styles build', () => {
let root: string;

beforeAll(() => {
root = mkdtempSync(join(tmpdir(), 'route-styles-full-'));
mkdirSync(join(root, 'app'), { recursive: true });
writeFileSync(join(root, 'app', 'page.tsx'), 'export default () => <p className="p-2 flex" />');
writeFileSync(
join(root, 'app', 'globals.css'),
`@tailwind base;\n${routeStyles.UTILITIES_MARK}\n@tailwind components;\n@tailwind utilities;\n`,
);
writeFileSync(
join(root, 'tailwind.config.cjs'),
`const { withRouteStylesTailwind } = require(${JSON.stringify(require.resolve('../../scripts/style-sources.cjs'))});\n` +
`module.exports = withRouteStylesTailwind({ content: [${JSON.stringify(join(root, 'app', 'page.tsx'))}] });`,
);
writeFileSync(
join(root, 'postcss.config.cjs'),
`module.exports = { plugins: { ${JSON.stringify(require.resolve('tailwindcss'))}: {} } }`,
);
});

afterAll(() => rmSync(root, { recursive: true, force: true }));

it('is built from the app’s own content, though the build step runs with NEXT_STYLES=routes', async () => {
process.env.NEXT_STYLES = 'routes';
try {
const build = await routeStyles.stylesheetBuilder({
root,
input: 'app/globals.css',
config: 'tailwind.config.cjs',
});
const full = await build(null);
expect(full).toContain('.p-2{');
expect(full).toContain('.flex{');
} finally {
delete process.env.NEXT_STYLES;
}
});
});

describe('route-styles: a finished build', () => {
let root: string;

Expand Down Expand Up @@ -288,13 +330,15 @@ describe('next-styles: the route-styles config wrappers', () => {
expect(fullSheetUrl({ buildId: 'b1', basePath: '/help/' })).toBe('/help/_next/static/next-styles/full-b1.css');
});

it('under next-styles build, build the root sheet with no utilities', () => {
it('under next-styles build, build the root sheet with no utilities and keep the app config', () => {
process.env.NEXT_STYLES = 'routes';
try {
expect(withRouteStylesTailwind({ content: ['a'], safelist: ['b'], theme: {} })).toEqual({
const app = { content: ['a'], safelist: ['b'], theme: {} };
expect(withRouteStylesTailwind(app)).toEqual({
content: [{ raw: '', extension: 'html' }],
safelist: [],
theme: {},
[APP_TAILWIND_CONFIG]: app,
});
} finally {
delete process.env.NEXT_STYLES;
Expand Down
Loading