Esri / jsapi-resources

A collection of resources for developers using the ArcGIS Maps SDK for JavaScript.
https://developers.arcgis.com/javascript/latest/
Apache License 2.0
706 stars 561 forks source link

Using Vite with custom Accessor classes #524

Open sebastianfrey opened 1 month ago

sebastianfrey commented 1 month ago

Recently I migrated a Typescript app from CRA to Vite that contained some classes that used Accessor decorators as described here. The problem, was that Vite failed to serve those classes, because Accessor decorators must be transpiled by typescript.

As solution, I have created a simple configurable Vite plugin, which allows to transform classes with custom Accessor decorators on the fly using typescript. I thought this might be useful for someone else in the future, so I wanted to share this plugin here:

vite-arcgis-plugin.ts

import tsc from 'typescript';
import type { Plugin } from 'vite';

function getCompilerOptions(tsconfig: string | undefined) {
  if (!tsconfig) {
    return {};
  }
  const { config } = tsc.readConfigFile(tsconfig, tsc.sys.readFile);
  return config.compilerOptions;
}

export interface ArcGISConfig {
  transpile: (id: string) => boolean;
  tsconfig?: string;
}

export function arcgis(config: ArcGISConfig): Plugin {
  const { transpile, tsconfig } = config;
  const compilerOptions = getCompilerOptions(tsconfig);

  return {
    name: 'arcgis',
    async transform(code, id) {
      if (transpile(id)) {
        const transpiledCode = await tsc.transpileModule(code, {
          compilerOptions,
        });
        return {
          code: transpiledCode.outputText,
          map: transpiledCode.sourceMapText ?? null,
        };
      }
      return null;
    },
  };
}

Inside vite.config.ts the plugin can used in the following way:

import { defineConfig } from 'vite';
import { arcgis } from './vite-arcgis-plugin';

export default defineConfig({
  plugins: [
    // other plugins
    arcgis({
      transpile: (id) => /packages\/arcgis/.test(id),
      tsconfig: './tsconfig.json',
    }),
  ]
});
andygup commented 1 month ago

Thanks @sebastianfrey. I was able to get Accessor decorators working in a test app by adding the following to the tsconfig.json using Vite 5.3.4 and TypeScript 5.5.3:

    "experimentalDecorators": true, 

I'll add a note to that SDK documentation page you mentioned above. I didn't see it mentioned anywhere that the core API is currently using legacy decorators.

For reference, in case others come across this thread, the error message will be similar to this: Expression expected (Note that you need plugins to import files that are not JavaScript).

sebastianfrey commented 1 month ago

Hi @andygup, thanks for your feedback on this.

Some additional notes:

For me the error message Expression expected only occurred when using @arcgis/core with @vitejs/plugin-react-swc.

When using @vitejs/plugin-react for transpiling React and JSX the error message is: [plugin:vite:react-babel] /path/to/file/which/useses/decorators.ts: Support for the experimental syntax 'decorators' isn't currently enabled


For @vitejs/plugin-react-swc it is enough to set tsDecorators to true in the react swc plugin options. No plugin for processing Accesor decorators is required here.

import reactSwc from "@vitejs/plugin-react-swc";

export default defineConfig({
  plugins: [
    reactSwc({
      // Requires experimentalDecorators in tsconfig
      tsDecorators: true,
    }),
  ]
});

Note: It's required, as stated out by @andygup, to set experimentalDecorators to true in tscofnig.json.


But for @vitejs/plugin-react things are different. The error message suggests, to add @babel/plugin-syntax-decorators to solve the issue, but unfortunately @arcigs/core requires that decorators are transpiled with typescript.

For more details see https://github.com/Esri/feedback-js-api-next/issues/169#issuecomment-1197333777.

So when using @vitejs/plugin-react, the shared arcgis plugin from this thread can be leverage when using Accessor decorators.