ItsJonQ / g2

✨ An experimental reimagining of WordPress components
http://g2-components.com/
MIT License
105 stars 12 forks source link

Build time style extraction notes #280

Closed sarayourfriend closed 3 years ago

sarayourfriend commented 3 years ago
  1. leave cx as it is but extend sheet.insert to cache styles into a globally accessible window cache when running in "extraction" mode (window.__STYLE_SYSTEM_EXTRACTION_MODE)
  2. where we cannot extract
    • calls to css inside of functions
    • styled components with interpolated props functions
      const FocusableComponent = styled.div`
          ${ props => props.isFocused ? 'color: blue' : 'color: red' }
      `
    • change these to use css and then pass them through cx
      const unfocusedStyle = css`
          color: red;
      `
      const focusedStyle = css`
          color: blue;
      `
      const FocusableComponent = ({ isFocused, className, ...props }) => {
          const classes = cx(isFocused ? focusedStyle : unfocusedStyle, className)
          return <div {...props} className={classes} />
      }
  3. build time extraction script

    • run the output webpack bundle(s) in extraction mode
    • in JSDom environment set window.__STYLE_SYSTEM_EXTRACTION_MODE = true then run output webpack bundle(s)
    • serialize the resulting window.__STYLE_SYSTEM_INSERTION_CACHE__ into a separate LOAD FIRST bundle that pushes the result to a window.__STYLE_SYSTEM_WARM_CACHE__
    • when the compiler runs the first time, it checks window.__STYLE_SYSTEM_WARM_CACHE__ and if it exists, call native sheet.insert for each value in the warmed cache.
    • Basically... in createCompiler:

      customEmotionInstance.sheet.insert = (
          /** @type {[rule: string]} */ ...args
      ) => {
          if ( window.__STYLE_SYSTEM_EXTRACTION_MODE__ ) {
              if ( ! window.__STYLE_SYSTEM_INSERTION_CACHE__ ) {
                  window.__STYLE_SYSTEM_INSERTION_CACHE__ = [];
              }
              window.__STYLE_SYSTEM_INSERTION_CACHE__.push( ...args );
          } else {
              // regular behavior
          }
      };
      
      if ( ! window.__STYLE_SYSTEM_EXTRACTION_MODE__ && window.__STYLE_SYSTEM_WARM_CACHE__ ) {
          window.__STYLE_SYSTEM_WARM_CACHE__.forEach( customEmotionInstance.sheet.insert );
      }
    • replace top level calls to css with assignments to the generated classname

      const focusedStyle = css`color: blue`;

      becomes

      const focusedStyle = "prefix-123abc";
      • How to do this with styled? Do we do something like the following

        const Styled = styled.div`color: blue`;

        becomes

        const $$Styled_Styles = css`color: blue`; // => this gets replaced with just the generated classname of course
        const $$Styled_Component = core.div;
        const Styled = (props) => {
            const className = cx($$Styled_Styles, props.className); // how do we get cx into scope?
            return createComponent( // how do we get createComponent into scope?
                $$Styled_Component,
                Object.assign({}, props, { className })
            );
        }

        and

        const StyledAnotherComponent = styled(AnotherComponent)`color: blue`;

        becomes

        const $$StyledAnotherComponent_Styles = css`color: blue`;
        const $$StyledAnotherComponent_Component = AnotherComponent;
        const StyledAnotherComponent = (props) => {
            const className = cx($$StyledAnotherComponent_Styles, props.className);
            return createComponent(
                $$StyledAnotherComponent_Component,
                Object.assign({}, props, { className })
            );
        }

        ehhhhhh not sure what to do here...

    • if extraction fails, fall back to run-time styles by not replacing the calls to css
    • make sure ThemeProvider in global mode works with this strategy
    • What is the benefit of this if we're not outputting a CSS file?
      • eliminating all top-level calls to css and styled :thinking:
      • we're basically just pre-loading the calls to css and styled that would have happened at runtime and making them happen
      • how much does hashing the styles cost? That's basically all we're able to cut out with this approach
      • Nope, this isn't going to work