ts-astroturf-tools

0.16.0 • Public • Published

ts-astroturf-tools [beta! 🚧]

npm npm Build Status Coverage Status

This package improves DX for astroturf users.

Compatible with astroturf@>=1.0.0-beta, typescript@>=4 and webpack@>=5! For compatibility with astroturf@>=0.9 <= 1, use ts-astroturf-tools@<=0.14.3.

Installation

yarn add -D ts-astroturf-tools
npm i --save-dev ts-astroturf-tools

Overview

Features are divided in three major categories:

  • linaria-like functionality
  • diagnostic messages
  • autocomplete for identifiers

linaria-like functionality

  • Use variables declared in other modules inside your CSS:

    // * before
    // impossible :(
    
    // * after
    // colors.tsx
    export const RED = 'red';
    
    // index.tsx
    import { css } from 'astroturf';
    import { RED } from './colors';
    
    const btn = css`
      color: ${RED};
    `;
    
    // works for 'stylesheet' and ...
    import { stylesheet } from 'astroturf';
    
    const { a } = stylesheet`
      .a {
        color: ${RED};
      }
    `;
    
    // .. styled components too!
    import styled from 'astroturf/react';
    
    const Button = styled.button`
      color: ${RED};
    `;

Diagnostic messages

These messages are available if you use plain stylesheet tag from astroturf.

There are two types of diagnostic messages:

  • warnings in case there is unused CSS

    Available via:

    • webpack loader
    • babel plugin
    • TS Language Service Plugin (VS Code)
    import { stylesheet } from 'astroturf';
    
    const { btn } = stylesheet`
      .btn {
        color: red;
      }
    
      .active {
        color: green;
      }
    `;

    The warning will look like this:

    /path/to/file.js:8:3:
      Identifier "active" is unused. Consider removing it from CSS.
    

    In VS Code the warning will become a suggestion:

  • errors in case there is missing CSS

    Available via:

    • webpack loader
    • babel plugin
    • TS Language Service Plugin (VS Code)
    import { stylesheet } from 'astroturf';
    
    const { btn, active } = stylesheet`
      .btn {
        color: red;
      }
    `;

    The error will look like this:

    /path/to/file.js:3:14:
      Identifier "active" is missing in corresponding CSS.
    

    In VS Code:

Autocomplete for identifiers

Available via:

  • TS Language Service Plugin (VS Code)

Quick summary of tools and their respective features

Tool Diagnostic messages Autocomplete for identifiers linaria-like functionality
TS Language Service Plugin N/A
webpack loader N/A optional
babel plugin N/A
TS transformer N/A
  • N/A - not applicable

Configuration

  • TS Language Service Plugin

    Add ts-astroturf-tools as a plugin to your tsconfig.json:

    {
      "compilerOptions": {
        "plugins": [
          {
            "name": "ts-astroturf-tools"
          }
        ]
      },
      "files": ["src/index.tsx"],
      "exclude": ["node_modules"]
    }

    Don't forget to switch to workspace typescript instance:

  • TS transformer:

    • raw TypeScript

      You should use ttypescript as a compiler.

      Add ts-astroturf-tools/transformer as a transformer to your tsconfig.json:

      {
        "compilerOptions": {
          "plugins": [
            {
              "transform": "ts-astroturf-tools/transformer"
            }
          ]
        },
        "files": ["src/index.tsx"],
        "exclude": ["node_modules"]
      }
    • webpack / ts-loader

      const transformer = require('ts-astroturf-tools/transformer');
      
      module.exports = {
        // ...
        module: {
          // ...
          rules: [
            {
              test: /\.tsx$/,
              use: {
                loader: 'ts-loader',
                options: {
                  // ...
                  getCustomTransformers: () => ({
                    before: [transformer()],
                  }),
                },
              },
            },
          ],
        },
      };
  • webpack loader

    Add ts-astroturf-tools/loader as a first loader for ts-files:

    module.exports = {
      // ...
      module: {
        rules: [
          // ...
          {
            test: /\.tsx?$/,
            use: [
              // works with any typescript loader
              'ts-loader',
              'astroturf/loader',
              'ts-astroturf-tools/loader',
            ],
          },
        ],
      },
    };

    Available options:

    Option name Type Description
    linaria boolean Enables linaria-like functionality.

    Defaults:

    module.exports = {
      // ...
      module: {
        rules: [
          // ...
          {
            test: /\.tsx?$/,
            use: [
              // works with any typescript loader
              'awesome-typescript-loader',
              'astroturf/loader',
              {
                loader: 'ts-astroturf-tools/loader',
                options: {
                  linaria: false,
                },
              },
            ],
          },
        ],
      },
    };
  • Babel plugin

    Add ts-astroturf-tools/babel-plugin to your babel plugins:

    module.exports = {
      presets: ['@babel/env', '@babel/preset-react'],
      plugins: ['ts-astroturf-tools/babel-plugin'],
    };

Known limitations

  • Regex-based parser is used to extract CSS class names.

  • Limited support for imports

    Supported extensions: .tsx, .ts, .js.

    Files must not contain side-effects, import other heavy modules and / or libraries and code that must be transpiled.

    This is ok:

    // a.js
    export const redColor = 'red';
    
    // b.js
    export const greenColor = 'green';
    export { redColor } from './a.js';
    
    // index.js
    import { greenColor, redColor } from './a.js';
    import styled from 'astroturf/react';
    
    const Button = styled.button`
      color: ${redColor};
      background: ${greenColor};
    `;

    This is not ok and will most likely result in an error:

    // a.js
    import * as React from 'react';
    import image from './someImage.png';
    export const redColor = 'red';
    
    export const Something = () => (
      <div style={{ background: `url(${image});` }}>Hello!</div>
    );
    
    // b.js
    export const greenColor = 'green';
    export { redColor } from './a.js';
    
    // index.js
    import { greenColor, redColor } from './a.js';
    import styled from 'astroturf/react';
    
    const Button = styled.button`
      color: ${redColor};
      background: ${greenColor};
    `;
  • Performance issues with imports (this issue is in progress of being fixed)

    As of now, files are parsed and executed for each encountered import.

    For example:

    // a.js
    export const RED = 'red';
    
    // b.js
    export { RED } from './a';
    export const GREEN = 'green';
    
    // ComponentA.js
    import styled from 'astroturf/react';
    import { GREEN } from './b';
    
    export const ComponentA = styled.div`
      color: ${GREEN};
    `;
    
    // ComponentB.js
    import styled from 'astroturf/react';
    import { RED } from './b';
    
    export const ComponentB = styled.div`
      color: ${RED};
    `;

    In this case both a.js and b.js will be parsed and executed twice (first for ComponentA.js and then for ComponentB.js). Keep this in mind and try to avoid creating large dependency trees.

  • Limited support for interpolations

    const WIDTH = '500px';
    
    // ok
    const { a } = stylesheet`
      .a {
        width: ${WIDTH};
      }
    `;
    const NAME = 'someClass';
    
    //        error
    //      vvvvvvvvv
    const { someClass } = stylesheet`
      .${NAME} {
        color: red;
      }
    `;
  • Only plain CSS is supported.

    Basic features of SASS/LESS/etc. may work:

    // simple nesting is ok
    const { someClass, anotherClass } = stylesheet`
      .someClass {
        color: red;
    
        &.anotherClass {
          border: 1px solid black;
        }
      }
    `;

    Advanced features will most probably not work:

    //                    error!
    //                 vvvvvvvvvvvv
    const { someClass, anotherClass } = stylesheet`
      @name: anotherClass;
    
      .someClass {
        color: red;
    
        &.@{name} {
          color: black;
        }
      }
    `;
  • It is not possible to show errors in case destructuring is not used:

    const classes = stylesheet`
      .a {
        color: red;
      }
    `;
    
    console.log(a.b); // <- no error

    This is not hugely important because you should always use css in the first place.

Package Sidebar

Install

npm i ts-astroturf-tools

Weekly Downloads

3

Version

0.16.0

License

MIT

Unpacked Size

50.9 kB

Total Files

27

Last publish

Collaborators

  • dkamyshov