Search code examples
javascriptvite

Can I avoid Vite transforming class fields from javascript files?


I have a project using Vite (below you can see the vite.config.js file and the jsconfig.json in case it matters), and I am facing the following problem. I have a class defined like

class Actor extends ActorBase {
  system;

  constructor (...) {
    super(...)
    ...
  }
...
}

When building, it gets transformed into something like

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};

class Actor extends ActorBase {
  constructor (...) {
    super(...)
    __publicField(this, "system");

    ...
  }
...
}

Is it possible to avoid this transformation?

Motivation

The code I'm working on is to be consumed by a web app (it's some sort of extension/plugin for that app). In particular, it is a system for the virtual tabletop FoundryVtt. This way of defining the class field with __publicField(...) clashes with the web app consuming the code (FoundryVtt), and avoids the correct initialisation of the field for some reason I don't understand but must have something to do with the internals of FoundryVtt.

What I've tried

I thought it had something to do with the config "useDefineForClassField" in the jsconfig.json, but I tried to set it both to true and false with no difference. Setting different values for the target won't avoid it either.

I have also tried to initialise the value of the class field by using system = super.system but that way also conflicts with the web app (FoundryVtt) behaviour.

Config files

// vite.config.js
import { defineConfig } from 'vite'
import copy from "rollup-plugin-copy";
import { svelte } from '@sveltejs/vite-plugin-svelte'
import path from 'path';

export default defineConfig({
  resolve: {
    alias: {...},
  },
  build: {
    outDir: 'dist',
    emptyOutDir: true,
    minify: false,
    lib: {
      name: 'animabf',
      entry: 'src/animabf.mjs',
      formats: ['es'],
    },
    rollupOptions: {
      output: {
        preserveModules: true,
        preserveModulesRoot: "src",
        entryFileNames: ({ name: fileName }) => {
          return `${fileName}.js`
        },
        assetFileNames: 'animabf.[ext]'
      }
    }
  },
  plugins: [
    svelte(),
    copy({...})
  ],
})
// jsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": false,
    "lib": ["dom", "dom.iterable", "esnext"],
    "types": ["svelte", "@types/jest", "@league-of-foundry-developers/foundry-vtt-types"],
    "paths": {
      ...
    },
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowJs": true,
    "checkJs": true,
    "strict": true,
    "strictNullChecks": true,
    "skipLibCheck": true,
    "outDir": "dist"
  },
  "include": ["src"],
  "exclude": ["./**/.*.test.*", "./**/__mocks__", "node_modules"]
}


Solution

  • Changing jsconfig.json shouldn't affect the compilation here -- it is used by the language server or by svelte-check only.

    Adding a more modern target (which doesn't need the polyfill) to vite.config.js works for me! That is:

    export default defineConfig({
      ...,
      build: {
        target: 'esnext',
        ...
      }
    });