agiledigital / typed-redux-saga

An attempt to bring better TypeScript typing to redux-saga.
MIT License
315 stars 33 forks source link

Incorrect vite-plugin-babel-macros and @vitejs/plugin-react order leads to yield* conversion failure #692

Open sebc-vm opened 1 year ago

sebc-vm commented 1 year ago

Description:

When using Vite.js, the conversion of yield* to yield performed by typed-redux-saga/macro can fail when the vite-plugin-babel-macros is placed after @vitejs/plugin-react in the project's configuration.

This issue arises in particular when a yield* expression is used in conjunction with the as TypeScript operator, as in the following example:

import {applyMiddleware, legacy_createStore as createStore} from "redux";
import createSagaMiddleware from "redux-saga";
import {call} from "typed-redux-saga/macro";

const sagaMiddleware = createSagaMiddleware();
const enhancer = applyMiddleware(sagaMiddleware);
createStore(_state => null, null, enhancer);

sagaMiddleware.run(function* () {
  (yield* call(alert, 'it works')) as void;
});

Reproduction Steps:

  1. Set up a minimal Vite.js project with the provided configuration.
  2. Observe the order of plugins in the vite.config.js file.
  3. Run the project using npx vite.

Expected Behavior:

The project should execute successfully, maintaining proper conversion of yield* to yield with the use of the typed-redux-saga/macro library.

Actual Behavior:

When the vite-plugin-babel-macros is placed after @vitejs/plugin-react in the Vite.js configuration, the yield* conversion is not performed as expected. This leads to runtime errors, such as:

TypeError: yield* (intermediate value) is not iterable
    at index.tsx:9:11
    ...

Example Project Configuration:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import macrosPlugin from "vite-plugin-babel-macros";

export default defineConfig({
  plugins: [react(), macrosPlugin()]
});

Environment:

Additional Context:

This issue affects the correct functioning of the typed-redux-saga macro when used in combination with vite-plugin-babel-macros and @vitejs/plugin-react.

When @vitejs/plugin-react runs first, the AST seems to be transformed incorrectly. For instance, (yield* call(alert, 'it works')) as void becomes yield* (call(alert, 'it works') as void). The extra TSAsExpression node inside the YieldExpression node breaks the simple scheme used by typed-redux-saga/macro.

While the actual issue seems to be with @vitejs/plugin-react, a simple work-around is to place vite-plugin-babel-macros before @vitejs/plugin-react in the configuration.