0.2.0 • Published 20 days ago

swc-plugin-enum-to-obj v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
20 days ago

swc-plugin-enum-to-obj

An SWC plugin to convert TypeScript enums into plain objects!

Installation

Install with your favorite package manager as devDependency.

npm i -D swc-plugin-enum-to-obj

Add plugin to wherever you have an SWC config (e.g. .swcrc file, swc-loader config, etc).

This plugin currently has no configuration. However you have to leave an empty object to meet SWC's API schema.

{
  jsc: {
    parser: {
      syntax: 'typescript',
      tsx: true,
    },
    experimental: {
      plugins: [
        ['swc-plugin-enum-to-obj', {}],
      ],
    }
  },
}

Motivation

TypeScript enums are useful if they are used in suitable ways. However the compiled code of enums makes trouble. In order to support enum merging, TypeScript compiles them into IIFEs. I bet most of you won't use this feature, but it pollutes our compiled code.

// Before
export enum SimpleNumber {
  Bar,
  Baz,
}

// TypeScript compiles the above code to:
export var SimpleNumber;
(function(SimpleNumber) {
    SimpleNumber[SimpleNumber["Bar"] = 0] = "Bar";
    SimpleNumber[SimpleNumber["Baz"] = 1] = "Baz";
})(SimpleNumber || (SimpleNumber = {}));

This indeed works. But when you are trying to make a library containing enums, you will notice that enums are NOT tree-shakeable (e.g. rollup, SWC minify).

The compiled IIFE is a side-effect function call as the view of static code analysis. It cannot be safely removed because the analyzer don't have an idea about what it is doing.

Now that we know it is constructing enum objects, we can do this for it. This plugin picks up these compiled enum IIFEs and convert them to object literals.

After converting, bundlers and minifiers will be pleasure to remove all unused object literals for you. (e.g. rollup, SWC minify).

Why convert IIFEs instead of enums themselves? See this issue.

Examples

// Before
enum SimpleNumber {
  Bar,
  Baz,
}

// After
var SimpleNumber = {
  "Bar": 0,
  0: "Bar",
  "Baz": 1,
  1: "Baz"
};
// Before
export enum SimpleString {
  A = 'Z',
  B = 'Y',
}

// After
export var SimpleString = {
  "A": 'Z',
  "B": 'Y'
};

Caveats

  • Enum merging might not work.

    This plugin strictly looks for the "var X + IIFE" pattern. Mergings will be left unchanged.

    // Before
    enum Foo { Bar = 1 }
    enum Foo { Baz = 2 }
    
    // After
    var Foo = {
        "Bar": 1,
        1: "Bar"
    };
    (function(Foo) {
        Foo[Foo["Baz"] = 2] = "Baz";
    })(Foo || (Foo = {}));
  • You might accidently convert enums of external libraries.

    It is a problem caused by converting IIFEs.

    If you are using libraries containing enums, and you make SWC process all node_modules file at the same time, those enums will be converted too because they also match the "var X + IIFE" pattern.

    This should not cause any problems. However I think you should notice this behavior.

  • Enums containing complex caclucations are not supported.

    This plugin strictly looks for number or string literals. However in some cases, SWC left calculation expressions stay in the IIFE. This kind of enums will be left unchanged.

    // Before
    enum Foo {
      A = 3,
      B = 2,
      C = 1,
      X = A ** B ** C,
    }
    
    // After
    var Foo;
    (function(Foo) {
        Foo[Foo["A"] = 3] = "A";
        Foo[Foo["B"] = 2] = "B";
        Foo[Foo["C"] = 1] = "C";
        Foo[Foo["X"] = Foo.A ** Foo.B ** Foo.C] = "X";
    })(Foo || (Foo = {}));
  • const enums are handled by SWC, not this plugin.

    SWC currently converts const enums the same way as normal enums. There will be an enum object as a result.

License

MIT

0.2.0

20 days ago

0.1.1

7 months ago

0.1.0

9 months ago