Linaria: Linaria with preact-cli & preact X

Created on 1 Jun 2019  ·  6Comments  ·  Source: callstack/linaria

Does anybody have experience with setting up Linaria with Preact-cli/Preact X?

I tried the following:
linaria moduleWrapper

"moduleNameMapper": {
            "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tests/__mocks__/fileMock.js",
            "\\.(css|less|scss)$": "identity-obj-proxy",
            "^./style$": "identity-obj-proxy",
            "^preact$": "<rootDir>/node_modules/preact/dist/preact.min.js",
            "^react$": "preact/compat",
            "^react-dom$": "preact/compat",
            "^linaria$": "preact/compat",
            "^create-react-class$": "preact-compat/lib/create-react-class",
            "^react-addons-css-transition-group$": "preact-css-transition-group"
        }

.babelrc

{
  "env": {
    "test": {
      "presets": [
        ["preact-cli/babel", { "modules": false }],
        "linaria/babel"
      ]
    }
  }
}

preact.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

export default {
    webpack(config, env, helpers, options) {
        // config.resolve.alias = Object.assign({}, config.resolve.alias, {
        //  react$: 'preact/compat/',
        //  'react-dom$': 'preact/compat',
        //  react: 'preact/compat/',
        //  'react-dom': 'preact/compat',
        //  linaria: 'preact/compat'
        // });

        config.plugins.push(new MiniCssExtractPlugin({ filename: 'styles.css' }));

        config.module.rules.push({
            test: /\.m?js$/,
            exclude: /(node_modules)/,
            use: [
                {
                    loader: 'babel-loader'
                },
                {
                    loader: 'linaria/loader'
                }
            ]
        });

        return config;
    }
};

The following error is returned:
bundle.esm.js:1593 Error: Using the "styled" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly. Is .babelrc not setup correctly?

Versions:
"linaria": "^1.3.1"
"preact": "^10.0.0-beta.2"
"preact-compat": "^3.17.0"
"preact-render-to-string": "^5.0.3"

documentation 📖 question ❔

All 6 comments

any update?

@ourfamilygithub IMO linaria is dead, forget about using with Preact

It looks like a problem with preact configuration: if you just push the new rule to the end of the rules list, it will not work because it already has a rule for js-files (https://github.com/preactjs/preact-cli/blob/d6fd760427ce957f588b714e347ce40121601917/packages/cli/lib/lib/webpack/webpack-base-config.js#L150). You probably need to modify an existing rule.

@secretlifeof

Hello, I think I found a way to make [email protected] work with [email protected]

Here is my setup:
New app created via:
npx preact-cli create default test

On top of the default template, I installed: @babel/preset-react. This is because for linaria to work with JSX syntax, it needs that preset. Otherwise, it will throw an error saying that linaria/loader can't parse JSX.

My package.json file looks like the following:

"devDependencies": {
    "@babel/preset-react": "^7.8.3", //Here is preset-react
    "enzyme": "^3.10.0",
    "enzyme-adapter-preact-pure": "^2.0.0",
    "eslint": "^6.0.1",
    "eslint-config-preact": "^1.1.0",
    "identity-obj-proxy": "^3.0.0",
    "jest": "^24.9.0",
    "jest-preset-preact": "^1.0.0",
    "per-env": "^1.0.2",
    "preact-cli": "^3.0.0-rc.6",
    "preact-render-spy": "^1.2.1",
    "sirv-cli": "^0.4.5"
  },
  "dependencies": {
    "linaria": "^1.3.3",
    "preact": "^10.3.2",
    "preact-render-to-string": "^5.1.4",
    "preact-router": "^3.2.1"
  },

Now, create a .babelrc file, with the following:

{
  "presets": ["@babel/preset-env", "@babel/preset-react", "linaria/babel"],
  "plugins": [
    "./node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js",
    "./node_modules/@babel/plugin-transform-object-assign/lib/index.js",
    [
      "./node_modules/@babel/plugin-proposal-decorators/lib/index.js",
      {
        "legacy": true
      }
    ],
    [
      "./node_modules/@babel/plugin-proposal-class-properties/lib/index.js",
      {
        "loose": true
      }
    ],
    "./node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js",
    "./node_modules/babel-plugin-transform-react-remove-prop-types/lib/index.js",
    [
      "./node_modules/@babel/plugin-transform-react-jsx/lib/index.js",
      {
        "pragma": "h",
        "pragmaFrag": "Fragment"
      }
    ],
    [
      "./node_modules/fast-async/plugin.js",
      {
        "spec": true
      }
    ],
    "./node_modules/babel-plugin-macros/dist/index.js"
  ]
}

The plugins listed here are based on preact's default template/cli, I just console logged them in preact.config.js and moved to the babelrc. I did not add/remove any of the default plugins.

Finally, in your preact.config.js, the following:

export default config => {
  const newBabelLoader = {
    test: /\.jsx?$/, //This one is a different regex from the standard one -> /\.m?[jt]sx?$/
    exclude: /node_modules/,
    enforce: "pre", //Don't delete this
    resolve: { mainFields: ["module", "jsnext:main", "browser", "main"] }, //Don't delete this
    use: [
      {
        loader: "babel-loader",
        options: {
          plugins: [] //Move your plugins to the .babelrc
        }
      },
      { loader: "linaria/loader" }
    ]
  };

  config.module.rules[0] = newBabelLoader; //override your babel-loader rule
};

For some reason, preact does not like when you push presets/plugins given to it from the preact config file (working with linaria), eg:

const babelLoaderRule = config.module.rules[0];
babelLoaderRule.options.presets.push('@babel/preset-react');
babelLoaderRule.options.presets.push('linaria/loader');

I also had to remove the first preset they use: @babel/preset-typescript, because I don't use it. I think that having the first preset (typescript) causes problems. After all that, you should be able to run npm run build, it should be green.

To test that your build succeded, go to any component file, in my case I picked components/header/index.js,

I added a linaria generated class name:

import { h } from "preact";
import { Link } from "preact-router/match";
import style from "./style.css";

import { css } from "linaria";

const className = css`
  color: red;
  font-weight: 800;
`;

const Header = () => (
  <header class={style.header}>
    <h1>Preact App</h1>
    <nav>
      <Link activeClassName={style.active} href="/">
        Home
      </Link>
      <Link activeClassName={style.active} href="/profile">
        Me
      </Link>
      <Link activeClassName={style.active} href="/profile/john">
        John
      </Link>
    </nav>
    <button class={className}>Hello</button> //here I use it
  </header>
);

export default Header;

Now build, and go to the build folder, and look for bundle.[hash].css, open it in an editor, formate it, and the class you created should be at the bottom.

If you run npm start, you should be able to see a button next to the nav title, with red bold text.

Let me know if this helps you, I struggled two days to make it work x'D

@Tsubasa1218 thank you for the solution :) It would be awesome if you could contribute and add a note to linaria documentation about preact configuration!

closed via #595

Was this page helpful?
0 / 5 - 0 ratings

Related issues

krvikash35 picture krvikash35  ·  6Comments

MaximeHeckel picture MaximeHeckel  ·  5Comments

Guria picture Guria  ·  3Comments

satya164 picture satya164  ·  3Comments

jpnelson picture jpnelson  ·  4Comments