wyw-in-js icon indicating copy to clipboard operation
wyw-in-js copied to clipboard

Feature: add next.js integration

Open mulfyx opened this issue 1 year ago • 8 comments
trafficstars

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

mulfyx avatar Dec 11 '23 21:12 mulfyx

Is Next.js 13 or 12 supported?

glassdimlygr avatar Jan 17 '24 17:01 glassdimlygr

@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 avatar Jan 30 '24 08:01 siriwatknp

@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 avatar Jan 30 '24 16:01 layershifter

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

Needs to be debugged to get understanding what went wrong.

layershifter avatar Feb 11 '24 19:02 layershifter

this might help I think

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

mulfyx avatar Feb 11 '24 20:02 mulfyx

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
  },
}

nihgwu avatar Feb 17 '24 14:02 nihgwu

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

mulfyx avatar Mar 14 '24 16:03 mulfyx

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.

brijeshb42 avatar Apr 01 '24 18:04 brijeshb42