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(react): enable support for CSS Modules and emitting *.css files in bundle #4800

Merged
merged 10 commits into from
Aug 1, 2024
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["docs", "example-*", "codesandbox", "rollup-plugin-import-css"]
"ignore": ["docs", "example-*", "codesandbox"]
}
5 changes: 5 additions & 0 deletions .changeset/dry-trainers-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': major
---

Update Primer React to emit *.css files that are imported by emitted *.js files for styling
2 changes: 1 addition & 1 deletion .github/workflows/consumer_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Install dependencies
run: npm ci
- name: Build @primer/react
run: npm run build -w @primer/react
run: npm run build -w rollup-plugin-import-css -w @primer/react
# Output the artifact as a tarball in `consumer-test`. Write the
# information for this package in `consumer-test/pack.json` so we can read
# from it later to install the package
Expand Down
63 changes: 63 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"name": "primer",
"private": true,
"workspaces": [
"packages/rollup-plugin-import-css",
"packages/*",
"docs",
"examples/*"
],
"scripts": {
"setup": "./script/setup",
"build": "npm run build -w @primer/react",
"build": "npm run build -w rollup-plugin-import-css -w @primer/react",
"clean": "npm run clean -ws --if-present",
"clean:all": "npm run clean && rimraf node_modules docs/node_modules packages/*/node_modules examples/*/node_modules",
"format": "prettier --cache --write '**/*.{js,css,md,mdx,ts,tsx,yml}'",
Expand Down
8 changes: 7 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
"./lib-esm/internal/*": null
},
"typings": "lib/index.d.ts",
"sideEffects": false,
"sideEffects": [
"lib-esm/**/*.css",
"lib/**/*.css"
],
"scripts": {
"build": "./script/build",
"clean": "rimraf dist lib lib-esm css",
Expand Down Expand Up @@ -199,7 +202,9 @@
"mdast-util-to-string": "4.0.0",
"micromark-extension-frontmatter": "2.0.0",
"micromark-extension-mdxjs": "3.0.0",
"postcss-custom-properties-fallback": "1.0.2",
"postcss-preset-env": "9.5.14",
"postcss-preset-primer": "^0.0.0",
"react": "18.3.1",
"react-dnd": "14.0.4",
"react-dnd-html5-backend": "14.0.2",
Expand All @@ -208,6 +213,7 @@
"recast": "0.23.7",
"rimraf": "5.0.5",
"rollup": "4.9.6",
"rollup-plugin-import-css": "^0.0.0",
"rollup-plugin-postcss": "4.0.2",
"rollup-plugin-visualizer": "5.9.2",
"semver": "7.6.2",
Expand Down
111 changes: 104 additions & 7 deletions packages/react/rollup.config.js → packages/react/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import fs from 'node:fs'
import path from 'node:path'
import {fileURLToPath} from 'node:url'
import commonjs from '@rollup/plugin-commonjs'
import resolve from '@rollup/plugin-node-resolve'
import babel from '@rollup/plugin-babel'
import replace from '@rollup/plugin-replace'
import terser from '@rollup/plugin-terser'
import glob from 'fast-glob'
import customPropertiesFallback from 'postcss-custom-properties-fallback'
import {visualizer} from 'rollup-plugin-visualizer'
import {importCSS} from 'rollup-plugin-import-css'
import postcss from 'rollup-plugin-postcss'
import postssPresetPrimer from 'postcss-preset-primer'
import MagicString from 'magic-string'
import packageJson from './package.json'
import packageJson from './package.json' assert {type: 'json'}

const __dirname = path.dirname(fileURLToPath(import.meta.url))

const input = new Set([
// "exports"
Expand Down Expand Up @@ -80,6 +88,50 @@ function createPackageRegex(name) {
return new RegExp(`^${name}(/.*)?`)
}

const postcssPlugins = [
postssPresetPrimer(),
customPropertiesFallback({
importFrom: [
() => {
let customProperties = {}
const filePaths = glob.sync(['fallbacks/**/*.json', 'docs/functional/themes/light.json'], {
cwd: path.join(__dirname, '../../node_modules/@primer/primitives/dist/'),
ignore: ['fallbacks/color-fallbacks.json'],
})

for (const filePath of filePaths) {
const fileData = fs.readFileSync(
path.join(__dirname, '../../node_modules/@primer/primitives/dist/', filePath),
'utf8',
)

const jsonData = JSON.parse(fileData)
let result = {}

if (filePath === 'docs/functional/themes/light.json') {
for (const variable of Object.keys(jsonData)) {
result[`--${variable}`] = jsonData[variable].value
}
} else {
result = jsonData
}

customProperties = {
...customProperties,
...result,
}
}

return {customProperties}
},
],
}),
]

const postcssModulesOptions = {
generateScopedName: 'prc-[folder]-[local]-[hash:base64:5]',
}

const baseConfig = {
input: Array.from(input),
plugins: [
Expand Down Expand Up @@ -121,12 +173,12 @@ const baseConfig = {
commonjs({
extensions,
}),
postcss({
extract: 'components.css',
autoModules: false,
modules: {generateScopedName: 'prc_[local]_[hash:base64:5]'},
// plugins are defined in postcss.config.js
importCSS({
modulesRoot: 'src',
postcssPlugins,
postcssModulesOptions,
}),

/**
* This custom rollup plugin allows us to preserve directives in source
* code, such as "use client", in order to support React Server Components.
Expand Down Expand Up @@ -269,7 +321,52 @@ export default [
'process.env.NODE_ENV': JSON.stringify('production'),
preventAssignment: true,
}),
...baseConfig.plugins,
babel({
extensions,
exclude: /node_modules/,
babelHelpers: 'inline',
babelrc: false,
configFile: false,
presets: [
'@babel/preset-typescript',
[
'@babel/preset-react',
{
modules: false,
},
],
],
plugins: [
'macros',
'add-react-displayname',
'dev-expression',
'babel-plugin-styled-components',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-optional-chaining',
[
'babel-plugin-transform-replace-expressions',
{
replace: {
__DEV__: "process.env.NODE_ENV !== 'production'",
},
},
],
],
}),
resolve({
extensions,
}),
commonjs({
extensions,
}),
// PostCSS plugins are defined in postcss.config.js
postcss({
extract: 'components.css',
autoModules: false,
modules: {
generateScopedName: 'prc_[local]_[hash:base64:5]',
},
}),
terser(),
visualizer({sourcemap: true}),
],
Expand Down
2 changes: 1 addition & 1 deletion packages/react/script/build
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ npm run clean
npm run build:precompile-color-schemes

# Bundle
npx rollup -c --bundleConfigAsCjs
npx rollup -c

# Type check
npx tsc --project tsconfig.build.json
Expand Down
11 changes: 11 additions & 0 deletions packages/react/script/get-export-sizes.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ async function main() {
commonjs({
include: /node_modules/,
}),
{
name: 'empty-css-modules',
transform(_code, id) {
if (!id.endsWith('.css')) {
return
}
return {
code: `export default {}`,
}
},
},
virtual({
__entrypoint__: `export { ${identifier} } from '${filepath}';`,
}),
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/__tests__/exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async function setup(): Promise<Project> {
}

const extension = path.extname(source)
if (extension !== '' && extensions.includes(extension)) {
if (extension !== '' && !extensions.includes(extension)) {
return null
}

Expand Down
17 changes: 12 additions & 5 deletions packages/rollup-plugin-import-css/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ export function importCSS(options: ImportCSSOptions): Plugin {
return
}

// If we're working with a css asset that is not a CSS module, assume that
// it has been generated by our plugin and should be marked as external.
if (source.endsWith('.css') && !source.endsWith('.module.css')) {
const moduleInfo = this.getModuleInfo(importer)
if (moduleInfo?.meta['import-css']?.source === source) {
return {
id: path.resolve(path.dirname(importer), source),
id: source,
external: true,
}
}
Expand Down Expand Up @@ -87,9 +86,17 @@ export function importCSS(options: ImportCSSOptions): Plugin {
fileName,
})

const moduleInfo = this.getModuleInfo(id)
const cssSource = `./${path.basename(fileName)}`
if (moduleInfo) {
moduleInfo.meta['import-css'] = {
source: cssSource,
}
}

return {
code: `
import './${path.basename(fileName)}';
import '${cssSource}';
export default ${JSON.stringify(cssModuleClasses)}
`,
}
Expand Down
Loading