Search code examples
typescriptweb-componentautoprefixerlit-element

How to use autoprefixer with web-components( litElement )?


In LitElement you can store your style as inline style directly in your component.ts(or .js):

@customElement('main-header')
export class MainHeader extends LitElement {
  static styles = css`
    p {
      background: red;
    }
  `;
}

or in separate file like style.ts:

\* mainHeaderStyles.ts *\
export default css`
    p {
      background: red;
    }
`;

\* MainHeader.ts *\
import mainHeaderStyles from './main-header.ts';

@customElement('main-header')
export class MainHeader extends LitElement {
  static styles = mainHeaderStyles;

but not in ".css", so bundlers(for now i'm using Parcel) can't find my style and add browsers prefixes.

I'm tried to use Webpack(then Rollup) and export ".css" file directly to component, bundlers can use autoprefixer in this way, but they can't inline my style with prefixes to component(they just merge all styles to 1(or more) output file).

I know about StencilJS but i don't want rewrite all my LitElement code.

Will happy to hear any solutions or suggestions on how to solve it.)


Solution

  • Using bundlers

    bundlers [...] just merge all styles to 1(or more) output file

    This actually depends on how you configured your bundler and what loaders/processors you're using. For example, this is a simple Rollup + Postcss + Autoprefixer configuration perfectly usable with lit:

    // rollup.config.js
    import resolve from 'rollup-plugin-node-resolve';
    import typescript from 'rollup-plugin-typescript2';
    import postcss from 'rollup-plugin-postcss';
    import autoprefixer from 'autoprefixer';
    
    export default {
      // ...
      plugins: [
        resolve(),
        postcss({
          plugins: [autoprefixer()],
          inject: false, // By default postcss also injects the
                         // styles in <head> which is pretty useless
                         // with LitElement's style encapsulation
        }),
        typescript(),
      ],
    }
    

    This way the processed css strings are available as default exports:

    import style from './style.css';
    

    The same thing can easily be done with Parcel or Webpack + postcss-loader.

    Adopting the imported stylesheets

    bundlers can use autoprefixer in this way, but they can't inline my style with prefixes to component

    I guess you mean that LitElement expects CSSResults in the styles property, not the plain css text. There are a couple of things you can do to make it work though:

    import {css, unsafeCSS, LitElement, customElement} from 'lit-element';
    import style from './style.css';
    
    @customElement('my-component')
    export class MyComponent extends LitElement {
      // Apply the css template tag to the style variable
      static styles = css([style]);
      // or use unsafeCSS
      static styles = unsafeCSS(style);
      // ...
    }
    

    If you're interested in the Rollup + Postcss solution: I built a Rollup plugin (rollup-plugin-postcss-lit) to adapt Postcss exported styles to lit, so that you don't have to manually transform them to CSSResults

    import {customElement, LitElement, css} from 'lit-element';
    import myStyles from './styles.css';
    import otherStyles from './other-styles.scss';
    
    @customElement('my-component')
    export class MyComponent extends LitElement {
      static styles = [myStyles, otherStyles, css`
        .foo {
          padding: ${...};
        }
      `];
    }