Anber / wyw-in-js

MIT License
191 stars 8 forks source link

Feature: add next.js integration #29

Open mulfyx opened 6 months ago

mulfyx commented 6 months ago

The current version of wyw-in-js does not provide compatibility with Next.js 14.

glassdimlygr commented 5 months ago

Is Next.js 13 or 12 supported?

siriwatknp commented 5 months ago

@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.

layershifter commented 5 months ago

@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 🐱

layershifter commented 4 months ago

Looks like the problem has repro https://github.com/callstack/linaria/issues/1387.

Needs to be debugged to get understanding what went wrong.

mulfyx commented 4 months ago

this might help I think

https://github.com/vanilla-extract-css/vanilla-extract/blob/6c65b4836cbc2db344524d7b613c9e445d87ea38/packages/webpack-plugin/src/loader.ts#L122

nihgwu commented 4 months ago

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

  1. create babel.config.js, we still need the babel plugin to compile wyw-in-js to classNames
    module.exports = {
      presets: ['next/babel', '@wyw-in-js'],
    }
  2. create script (e.g. extract-styles.mjs) to extract style via esbuild

    import 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')
    }
  3. import styles.css in _app.tsx of Next.js app
  4. 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
  },
}
mulfyx commented 3 months ago

https://github.com/mui/material-ui/tree/master/packages/pigment-css-react#start-with-nextjs 👀

brijeshb42 commented 3 months ago

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.