alephjs / aleph.js

The Full-stack Framework in Deno.
https://aleph.deno.dev/
MIT License
5.26k stars 168 forks source link

CSS-in-JS Support? #90

Open shadowtime2000 opened 3 years ago

shadowtime2000 commented 3 years ago

A ton of people like CSS-in-JS and I think we should add support for it. We have to figure out how we will do it. I see 2 options:

  1. Write our own using SWC macros once released #78
  2. Add support for something like styled-components, though we would have to write our own SSR compiler thing
shadowtime2000 commented 3 years ago

An example of it with macros:

// macro source

export default function Styled(initialCSS, ...values) {
    return "";
}

Styled.macro = {
    transform(initialCSS, ...values) {
        let outputCSS = "";
        let valueCounter = 0;
        const id = Math.random().toString(36).slice(2);
        initialCSS.forEach(intial => {
            outputCSS += initial;
            outputCSS += values[valueCounter];
            valueCounter++;
        });
        return `
        (() => {
            const styleElem = document.createElement("style");
            styleElem.textContent = ".styled-${id}{${intialCSS}}";
            document.head.appendChild(styleElem);
            return "styled-${id}";
        })();
        `
    }
}
// source code

const className = styled`
    color: red;
    background-color: grey;
`;
// compiled code

const className = (() => {
    const styleElem = document.createElement("style");
    styleElem.textContent = ".styled-asdfi4788837{color: red;background-color:grey;}";
    document.head.appendChild(styleElem);
    return "styled-asdfi4788837";
})();
shadowtime2000 commented 3 years ago

styled-components/styled-components#3382

ije commented 3 years ago

0.3 will support inline css like:

export default function App() {
  return (
    <>
      <h1>Hello World</h1>
      <style>{`
        h1 {
          color: #d63369;
        }
      `}</style>
    </>
  )
}
shadowtime2000 commented 3 years ago

@ije Cool, but as far as I am aware that is very basic CSS-in-JS. Most CSS-in-JS frameworks support stuff like theming and dynamic styles too.

thegaryroberts commented 3 years ago

I'm using the framework agonistic version of Emotion (CSS-in-JS) in Aleph.js without any effort: https://emotion.sh/docs/@emotion/css

using the esm.sh import in my import_map.json:

{
    "imports": {
     ...
      "@emotion/css": "https://esm.sh/@emotion/css@11.1.3",
     ...
    }
}

then in my calling code:

import { css } from "@emotion/css";

const ulStyles = css`
  display: flex;
  list-style-type: none;
  margin: 0;
  padding: 10px 0 0 10px;

  li {
    margin: 0 10px 10px 0;
    padding: 5px 8px;

    a {
        color: hsl(214, 100%, 71%);
        text-decoration: none;
    }

    &:hover {
        background-color: hsl(210, 0%, 90%);
    }
  }
`;

export const MainNav = () => {
  return (
    <ul className={ulStyles}>
       <li><a>
    ....

also the global css in the app.tsx file:

import { injectGlobal } from "@emotion/css";

injectGlobal`
  * {
    box-sizing: border-box;
    font-family: 'Open Sans', sans-serif;
  }
`;

export default function App(
...

Didn't know where to begin with getting the react version working (https://emotion.sh/docs/@emotion/react) and it's custom jsx transform, without babel. Not sure if the new JSX transform in React will help or hinder this: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

In any case this framework agnostic CSS-in-JS solution is already a massive improvement for me over SASS/LESS/CSS.

shadowtime2000 commented 3 years ago

@thegaryroberts Thanks for sharing how you do it, I think Emotions React pkg has out of the box support with renderToString and other React SSR stuff. We should probably add support for /** @jsx */, though it is also possible to just call jsx because it is compatible with React.createElement.

thegaryroberts commented 3 years ago

So the main hurdle i faced without @jsx directive support, is when I tried this (as per emotion documented example):

/** @jsx jsx */
import { jsx, css, Global, ClassNames } from '@emotion/react'

the jsx value gets clean up/removed from the import by the deno fmt as it assumes it is not referenced.

shadowtime2000 commented 3 years ago

@thegaryroberts I think you could open an issue for that because afaik deno fmt is for formatting, not stuff like this which could fit deno lint more.

thegaryroberts commented 3 years ago

It turns out it was my IDE (VS Code) removing it. The directive is not removed if it is the very first line in the file. However this just led onto other issues getting emotion/react to work. Tried using the esm.sh import bundle options, but is still delivering emotion with inbuilt react version which leads to multiple react version warnings (and probable errors). Anyway giving up and sticking to emotion/css for now.

(A shame as emotion/react is a true component based approach to CSS. In my opinion modern projects should consider it as the starting point for CSS integration, instead of separate file css/sass approaches. We benefit from a consolidated componentisation approach to JS & HTML, e.g. React. Why exclude CSS from the componentisation paradigm).

nkia-christoph commented 3 years ago

Hey @thegaryroberts,

I've been trying to get emotion to work but keep running into the same error when calling css:

const navbar = css`
  color: red;
  background-color: hotpink;
  font-size: 20rem;
  text
`
Error: document is not defined

ReferenceError: document is not defined
    at createCache2 (file:///D:/70_research/deno/resume/app/.aleph/development/-/cdn.esm.sh/v41/@emotion/cache@11.1.3/deno/cache.development.js:132:25)
    at createEmotion2 (file:///D:/70_research/deno/resume/app/.aleph/development/-/cdn.esm.sh/v41/@emotion/css@11.1.3/deno/css.development.js:53:18)
    at file:///D:/70_research/deno/resume/app/.aleph/development/-/cdn.esm.sh/v41/@emotion/css@11.1.3/deno/css.development.js:155:22

using deno 1.11 and aleph 0.3.0-alpha.33

Is it still working for you?