Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add postcss-plugin #781

Merged
merged 5 commits into from
Nov 26, 2024
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
1 change: 1 addition & 0 deletions apps/nextjs-example/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import './globals.css';
import './stylex.css';
import { globalTokens as $ } from '@/app/globalTokens.stylex';
import * as stylex from '@stylexjs/stylex';

Expand Down
15 changes: 15 additions & 0 deletions apps/nextjs-example/app/stylex.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/

/**
* The @stylex directive is used by the @stylexjs/postcss-plugin.
* It is automatically replaced with generated CSS during builds.
*/

@stylex;
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
const path = require('path');
module.exports = {
presets: ['next/babel'],
Expand All @@ -8,6 +16,7 @@ module.exports = {
// https://stylexjs.com/docs/api/configuration/babel-plugin/
{
dev: process.env.NODE_ENV === 'development',
runtimeInjection: false,
javascripter marked this conversation as resolved.
Show resolved Hide resolved
genConditionalClasses: true,
treeshakeCompensation: true,
aliases: {
Expand Down
14 changes: 2 additions & 12 deletions apps/nextjs-example/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,7 @@
*/

/** @type {import('next').NextConfig} */
const path = require('path');
const stylexPlugin = require('@stylexjs/nextjs-plugin');
const babelrc = require('./.babelrc.js');
const plugins = babelrc.plugins;
const [_name, options] = plugins.find(
(plugin) => Array.isArray(plugin) && plugin[0] === '@stylexjs/babel-plugin',
);
const rootDir = options.unstable_moduleResolution.rootDir ?? __dirname;
const aliases = options.aliases ?? undefined;
const useCSSLayers = options.useCSSLayers ?? undefined;

module.exports = stylexPlugin({ rootDir, aliases, useCSSLayers })({
module.exports = {
transpilePackages: ['@stylexjs/open-props'],
});
};
5 changes: 1 addition & 4 deletions apps/nextjs-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
"private": true,
"scripts": {
"clean": "rimraf .next",
"predev": "npm run clean",
"prebuild": "npm run clean",
"dev": "next dev",
"build": "next build",
"start": "next start",
Expand All @@ -20,9 +18,8 @@
"next": "14.0.1"
},
"devDependencies": {
"@stylexjs/babel-plugin": "^0.7.5",
"@stylexjs/eslint-plugin": "^0.7.5",
"@stylexjs/nextjs-plugin": "^0.7.5",
"@stylexjs/postcss-plugin": "^0.9.3",
"@types/node": "^22.7.6",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
Expand Down
57 changes: 57 additions & 0 deletions apps/nextjs-example/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/

const fs = require('fs');
const path = require('path');

const projectRoot = __dirname;
const monorepoRoot = path.join(projectRoot, '../../');

function getPackageIncludePaths(packageName, nodeModulePaths) {
let packagePath = null;

for (const nodeModulePath of nodeModulePaths) {
const packageJsonPath = path.resolve(
nodeModulePath,
packageName,
'package.json',
);
if (fs.existsSync(packageJsonPath)) {
packagePath = path.dirname(packageJsonPath);
break;
}
}
if (!packagePath) {
throw new Error(`Could not find package ${packageName}`);
}

return [
path.join(packagePath, '**/*.{js,mjs}'),
'!' + path.join(packagePath, 'node_modules/**/*.{js,mjs}'),
];
}

const openPropsIncludePaths = getPackageIncludePaths('@stylexjs/open-props', [
path.join(projectRoot, 'node_modules'),
path.join(monorepoRoot, 'node_modules'),
]);

module.exports = {
plugins: {
'@stylexjs/postcss-plugin': {
include: [
'app/**/*.{js,jsx,ts,tsx}',
'components/**/*.{js,jsx,ts,tsx}',
...openPropsIncludePaths,
],
Comment on lines +48 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so I can verify how the postcss plugin works:

We're fining all files that match these globs and compiling them as a list.

Since we're reading all the files manually anyway, if we wanted to we could accept a list of "entrypoints" instead and resolve the dependency graph, right?

Copy link
Contributor Author

@javascripter javascripter Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're reading all the files manually anyway, if we wanted to we could accept a list of "entrypoints" instead and resolve the dependency graph, right?

Yes. The postcss plugin globs and compiles all matching files to extract css.
This means we may be over-compiling in some cases similar to how Tailwind CLI does it with the content glob.

We can accept entry points and resolve dependency graphs ourselves but we need to take into account aliases, configured platform extensions (.web.ts), and so on in some cases to replicate bundler dependency graphs so I avoided that to allow greater flexibility to users and to be bundler-agnostic in general.

Dependency graph resolvers are often a source of subtle bugs that aren't easy for users to fix unless there's an escape hatch, so I wrote getPackageIncludePaths function in postcss.config.js instead of integrating it within the postcss plugin so users can adjust it for their setup manually.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this all makes sense. Thanks!

useCSSLayers: true,
javascripter marked this conversation as resolved.
Show resolved Hide resolved
},
autoprefixer: {},
},
};
Loading