wyw-in-js
wyw-in-js copied to clipboard
Feature: add next.js integration
The current version of wyw-in-js does not provide compatibility with Next.js 14.
Is Next.js 13 or 12 supported?
@layershifter MUI is working on the zero-runtime engine (on top of linaria). Would you be able to share what's to be done for Next.js integration? I can submit a PR once the plan is clear.
@siriwatknp first, I would check if setup the existing Webpack loader & plugin works with Next.js 13/14 and debug what breaks. So far, I was not able to do that, but Next.js must be supported, so I appreciate if somebody will at least trace the problem 🐱
Looks like the problem has repro https://github.com/callstack/linaria/issues/1387.
Needs to be debugged to get understanding what went wrong.
this might help I think
https://github.com/vanilla-extract-css/vanilla-extract/blob/6c65b4836cbc2db344524d7b613c9e445d87ea38/packages/webpack-plugin/src/loader.ts#L122
As we still don't have official plugin for Next.js, and I've tried different solutions mentioned in this and other threads, none of them works for me (wyw-in-js + Next.js v14), so I chose another approach and works pretty good for us: Extracting stylesheet in a different process via esbuild, and esbuild is already super fast
- create
babel.config.js, we still need the babel plugin to compile wyw-in-js to classNamesmodule.exports = { presets: ['next/babel', '@wyw-in-js'], } - create script (e.g.
extract-styles.mjs) to extract style viaesbuildimport wyw from '@wyw-in-js/esbuild' import * as esbuild from 'esbuild' import fs from 'fs' import wywConfig from './wyw-in-js.config.js' const args = process.argv.slice(2) /** @type {import('esbuild').Plugin} */ const myPlugin = { name: 'my-plugin', setup(build) { build.onEnd(() => { const cssText = fs.readFileSync('./dist/index.css', 'utf-8') fs.writeFileSync('./styles.css', cssText, 'utf-8') fs.rmSync('./dist', { recursive: true }) }) }, } /** @type {import('esbuild').BuildOptions} */ const options = { entryPoints: ['src/index.ts'], outdir: 'dist', bundle: true, minify: false, logOverride: { 'ignored-bare-import': 'silent', }, plugins: [ wyw({ filter: wywConfig.include, ...wywConfig, }), myPlugin, ], } if (args.includes('-w') || args.includes('--watch')) { const context = await esbuild.context(options) await context.watch() // eslint-disable-next-line no-console console.log('👀 watching changes to generate styles.css') } else { await esbuild.build(options) // eslint-disable-next-line no-console console.log('✅ styles.css generated') } - import
styles.cssin_app.tsxof Next.js app - build styles while starting Next.js app
"dev": "node extract-styles.mjs & next dev
Note, if you are using Linaria in a different folder as us, you will need to do some trick to make sure babel plugin and esbuild plugin generate the same classNames, overriding classNameSlug in wyw.config.js
const { slugify } = require('@wyw-in-js/shared')
const { toValidCSSIdentifier } = require('@wyw-in-js/processor-utils')
module.exports = {
...
// TODO: we can remove this once https://github.com/Anber/wyw-in-js/pull/63 been merged, and only override it in website
classNameSlug: (hash, title, args) => {
const slug = toValidCSSIdentifier(
`${title.charAt(0).toLowerCase()}${slugify(
args.file.replace(/(.*\/ui-kit\/)src/, 'src'),
)}`,
)
const className = `${toValidCSSIdentifier(title)}_${slug}`
return className
},
}
https://github.com/mui/material-ui/tree/master/packages/pigment-css-react#start-with-nextjs 👀
You can try and use @pigment-css/nextjs-plugin with linaria and it should work. It has some MUI specific handling as well but that should not affect the usage of linaria.