Coder Social home page Coder Social logo

sukkaw / style9-webpack Goto Github PK

View Code? Open in Web Editor NEW
18.0 3.0 2.0 688 KB

The another Webpack Plugin for Atomic CSS-in-JS implementation style9

Home Page: https://github.com/johanholmerin/style9

License: MIT License

TypeScript 98.67% JavaScript 0.67% CSS 0.66%
css typescript css-in-js webpack atomic-css

style9-webpack's Introduction

style9-webpack

Created by Johan Holmerin, style9 is a CSS-in-JS compiler inspired by Facebook's stylex, with near-zero runtime, atomic CSS extraction, and TypeScript support. Framework agnostic.

style9-webpack is an alternative webpack plugin for style9.

Motivation

ATTENTION! Please please please read this first before you install style9-webpack!

style9 is a CSS-in-JS compiler, which means you will write your CSS in your JavaScript/JSX/TSX. But unlike other CSS-in-JS solutions, style9 provides an AoT Compiler. style9 will read your source code, collect your style and transform your JS/JSX/TSX, stripping runtime calls as much as possible (making the value of className a static string literal), and output CSS elsewhere. For more details about how style9 works, please check out style9's documentation.

style9 does provide a webpack plugin. It uses webpack-virtual-modules under the hood. During the compilation, style9 collects your styles and writes collected CSS into virtual modules. MiniCssExtractPlugin later will extract those virtual css files.

However, webpack-virtual-modules doesn't work well with Next.js. Next.js launches multiple webpack compiler instances to compile its server-side and client-side code separately. And webpack-virtual-modules just doesn't work when it is being shared between multiple webpack compiler instances.

I start this project as a Proof of Concept, to see if it is possible to make a webpack plugin for style9 that doesn't require webpack-virtual-modules. I use the virtualFileLoader idea from Vanilla Extract, another CSS-in-JS compiler. You can find the implementation of Vanilla Extract's virtualFileLoader here.

You most likely want to use style9's built-in webpack plugin instead. It works well for most cases. style9-webpack is just a Proof of Concept. But if you are using Next.js 13, and you are having trouble with style9's built-in Next.js plugin, you can give style9-webpack a shot.

Differences

The main differences between style9's built-in webpack plugin and style9-webpack are as follows:

style9-webpack loader doesn't have an inlineLoader option

style9's built-in webpack loader has an inlineLoader option. It allows you to chain other webpack loaders (like css-loader) to process the collected virtual css, like this:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(tsx|ts|js|mjs|jsx)$/,
        use: [{
          loader: Style9Plugin.loader,
          options: {
            inlineLoader: `!${MiniCssExtractPlugin.loader}!css-loader`,
            ...otherStyle9Options
          }
        }]
      }
      // ...
    ];
  });
}

style9-webpack doesn't support this approach. Instead, you will need add an extra rule to provide your loaders:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(tsx|ts|js|mjs|jsx)$/,
        use: [{
          loader: Style9Plugin.loader,
          options: {
            // Now style9-webpack will use "xxxx.style9.css" as the virtual css filenames
            virtualFileName: '[path][name].[hash:base64:7].style9.css',
            ...otherStyle9Options
          }
        }]
      },
      // And you create another rule to match the virtual css files. Now you can apply loaders to them.
      {
        test: /\.style9.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      // ...
    ];
  });
}

style9-webpack doesn't support Gatsby

You should use style9's built-in gatsby plugin instead. See style9's documentation for usage with Gatsby.

Installation

# NPM
npm i style9-webpack
# Yarn
yarn add style9-webpack
# PNPM
pnpm add style9-webpack

Usage

Webpack

// webpack.config.js
const Style9Plugin = require('style9-webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  // Collect all styles in a single file - required
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          type: 'css/mini-extract',
          chunks: 'all',
          enforce: true,
        }
      }
    }
  },
  module: {
    rules: [
      {
        test: /\.(tsx|ts|js|mjs|jsx)$/,
        use: Style9Plugin.loader,
        options: {
          virtualFileName: '[path][name].[hash:base64:7].style9.css', // {string?} optional, default is '[path][name].style9.css'
          parserOptions: {}, // {import('@babel/core').ParserOptions} optional, default is `{ plugins: ['typescript', 'jsx'] }`
          minifyProperties: process.env.NODE_ENV === 'production', // {boolean?} optional, default is false, recommended to enable this option in production
          incrementalClassnames: false, // {boolean?} optional, default is false
        }
      },
      {
        test: /\.style9.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new Style9Plugin(),
    new MiniCssExtractPlugin()
  ]
};

Next.js

// next.config.js
const withStyle9 = require('style9-webpack/next');

module.exports = withStyle9({
  parserOptions: {}, // // {import('@babel/core').ParserOptions} optional, default is `{ plugins: ['typescript', 'jsx'] }`
  minifyProperties: process.env.NODE_ENV === 'production', // {boolean?} optional, default is false, recommended to enable this option in production
  incrementalClassnames: false, // {boolean?} optional, default is false
})({
  // Your Next.js config goes here.
});

Next.js (appDir)

Currently, style9-webpack/next doesn't work well with Next.js appDir when "style9.create" is used in Server Components, due to a Next.js internal implementation detail. See #1 for more information.

In the meantime, you can use style9-webpack/next-appdir instead. It is a plugin specially designed to workaround the Next.js internal implementation quirk and can work with Next.js 13 beta appDir perfectly.

// next.config.js
const withStyle9 = require('style9-webpack/next-appdir');

module.exports = withStyle9({
  parserOptions: {}, // // {import('@babel/core').ParserOptions} optional, default is `{ plugins: ['typescript', 'jsx'] }`
  minifyProperties: process.env.NODE_ENV === 'production', // {boolean?} optional, default is false, recommended to enable this option in production
  incrementalClassnames: false, // {boolean?} optional, default is false
})({
  // Your Next.js config goes here.
});

Author

style9-webpack © Sukka, Released under the MIT License.
Authored and maintained by Sukka with help from contributors (list).

Personal Website · Blog · GitHub @SukkaW · Telegram Channel @SukkaChannel · Twitter @isukkaw · Mastodon @[email protected] · Keybase @sukka

style9-webpack's People

Contributors

dwlad90 avatar sukkaw avatar txhawks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

dwlad90 txhawks

style9-webpack's Issues

Styles extraction doesn't work in server components (Workaround Available~! See comments)

Maintainer Edits/Notes:

For those who want to use style9 in Next.js 13's appDir + Server Components, use style9-webpack/next-appdir instead of style9-webpack/next for now.

For those who want to know why style9 might not work with Next.js 13's appDir, check out https://github.com/SukkaW/style9-webpack#motivation and #1 (comment)


The plugin seems to work great with client components in the app dir, but not in server components.

Here is a very basic reproduction:
https://codesandbox.io/p/sandbox/ew8bdq

Can you spot anything wrong with our setup?

From the testing we've done, it would seem like Style9 itself works fine. If a server component uses a class that is also used in a client component (e.g., both use color: green;), the server component has the correct class and is painted green. However, if the server component uses a style that isn't used in any client component, say color: gold;, it will have a class on it that does not exist in the extracted css file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.