0.1.0-alpha.5 • Published 7 months ago

swc-plugin-react-refresh v0.1.0-alpha.5

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

swc-plugin-react-refresh

Swc plugin implementation of react-refresh/babel

npm

!IMPORTANT A plugin for developing bundlers

!WARNING This plugin is experimental.

  • Explore React components in module
    • Function expressions
    • Arrow function expressions
    • Class declarations
    • Import statements(default, named)
    • Export statements(default, named, named with declare)
  • Get component name from AST
  • Parse hook calls from AST
  • Parse HoC(High Order Component) expressions(React.memo, React.forwardedRef, and Custom HoC)
    • Wrapped components
    • Original components
  • Generate signature key based on the order of hook call expressions Use moduleId options instead

Setup

Requirements: >= @swc/core@1.3.81

npm install swc-plugin-react-refresh
# or yarn
yarn add swc-plugin-react-refresh

Add plugin to your swc options.

import { transform } from '@swc/core';

await transform(code, {
  jsc: {
    experimental: {
      plugins: [
        // Add plugin here
        ['swc-plugin-react-refresh', {
          /**
           * moduleId: string;
           * 
           * Module id (eg. generated id by bundler)
           */
          moduleId: "",
          /**
           * skipEnvCheck?: boolean;
           * 
           * Plugin available on only development environment.
           * If you want to use plugin in production, set `skipEnvCheck` to `true`.
           */
          skipEnvCheck: true,
        }],
      ],
    },
  },
});

Finally, inject runtime code at the top of bundled source.

const RefreshRuntime = require('react-refresh/runtime');


const ModuleMap = typeof WeakMap === 'function' ? WeakMap : Map;
const modules = new ModuleMap();

const isReactRefreshBoundary = (type) => {
  return RefreshRuntime.isLikelyComponentType(type) && !type.prototype.isReactComponent;
}

const createHmrContext = (type) => {
  if (!isReactRefreshBoundary(type)) {
    return {
      accept: () => undefined,
      dispose: () => undefined,
    };
  }

  const state = {
    timeout: null,
    accepted: false,
    disposed: false,
  };

  const hot = {
    accept: () => {
      if (state.disposed) {
        throw new Error('HMR module was disposed');
      }
  
      if (state.accepted) {
        throw new Error('HMR already accepted');
      }

      state.accepted = true;
      state.timeout = setTimeout(() => {
        state.timeout = null;
        RefreshRuntime.performReactRefresh();
      }, 50);
    },
    dispose: () => {
      state.disposed = true;
    },
  };

  if (modules.has(type)) {
    modules.get(type).dispose();
  }
  modules.set(type) = hot;

  return hot;
};

// `global` is platform dependent.
RefreshRuntime.injectIntoGlobalHook(global);
global.$RefreshReg$ = () => {};
global.$RefreshSig$ = () => (type) => type;
global.$RefreshRuntime$ = {
  getRegisterFunction: () => {
    return (type, id) => {
      if (!isReactRefreshBoundary(type)) return;
      RefreshRuntime.register(type, id);
    };
  },
  getCreateSignatureFunction: () => {
    return () => {
      const signature = RefreshRuntime.createSignatureFunctionForTransform();
      return (type, id, forceReset, getCustomHooks) => {
        if (!isReactRefreshBoundary(type)) return;
        signature(type, id, forceReset, getCustomHooks);
      }
    };
  },
  getContext: (type) => createHmrContext(type),
};

Development

cargo build

# release build
yarn build # target: wasm32-wasi
# or
cargo build-wasi --release # target: wasm32-wasi
cargo build-wasm32 --release # target: wasm32-unknown-unknown

# run unit tests
cargo test

# run on @swc/core
yarn demo

License

MIT

0.1.0-alpha.5

7 months ago

0.1.0-alpha.4

7 months ago

0.1.0-alpha.3

7 months ago

0.1.0-alpha.2

7 months ago

0.1.0-alpha.1

7 months ago

0.1.0-alpha.0

7 months ago