Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

ui-hmr

Hot module replacement transforms for Remix UI components, with integrations for Node and remix/assets.

ui-hmr rewrites supported Remix UI component modules so they can use the standard import.meta.hot APIs provided by packages like assets and node-hmr.

Features

  • Stable Components - Keep component identity stable while swapping implementations
  • Remount Fallbacks - Mark components stale when their setup scope changes
  • Node Module Hooks - Transform server component modules through Node's module customization hooks API
  • Assets Loader - Transform component modules for the browser through remix/assets

Installation

npm i remix

Usage

Use remix/ui-hmr/node as a Node import hook for server modules:

node --import remix/node-tsx --import remix/ui-hmr/node ./server.ts

Use uiHmr() from remix/ui-hmr/assets with remix/assets for browser modules:

import { createAssetServer } from 'remix/assets'
import { uiHmr } from 'remix/ui-hmr/assets'

let isDevelopment = process.env.NODE_ENV === 'development'

let assetServer = createAssetServer({
  basePath: '/assets',
  fileMap: { '/app/*path': 'app/*path' },
  allowFiles: ['app/**'],
  hmr: isDevelopment
    ? async () => (await import('remix/node-hmr/runtime')).createBrowserHmrChannel()
    : undefined,
  scripts: {
    loaders: isDevelopment ? [uiHmr()] : undefined,
  },
  watch: isDevelopment,
})

Direct Transforms

Use the direct transform APIs when you are writing your own loader, Node module hooks, or build integration.

import { transformComponentsForBrowser } from 'remix/ui-hmr'

let result = transformComponentsForBrowser(source, {
  importSource: 'remix',
  moduleUrl: '/assets/app/routes.tsx',
})

if (result.transformed) {
  console.log(result.componentNames)
}

transformComponentsForBrowser(source, options) rewrites browser component modules and emits import.meta.hot.accept() code for browser updates. The direct transform uses importSource to derive imports for the UI refresh runtime and browser HMR runtime.

import { transformComponentsForServer } from 'remix/ui-hmr'

let result = transformComponentsForServer(source, {
  importSource: 'remix',
  moduleUrl: 'file:///app/routes.tsx',
})

transformComponentsForServer(source, options) rewrites server component modules and registers updated component implementations for the current module URL. The direct transform uses importSource to derive imports for the server HMR runtime.

Both transforms return:

type ComponentsHmrTransformResult = {
  code: string
  componentNames: string[]
  map: string | null
  transformed: boolean
}

Pass sourceMap: true to generate a source map.

Use importSource to define where injected imports come from, typically either remix or @remix-run:

transformComponentsForBrowser(source, {
  importSource: 'remix',
  moduleUrl: '/assets/app/routes.tsx',
})

transformComponentsForServer(source, {
  importSource: 'remix',
  moduleUrl: 'file:///app/routes.tsx',
})

importSource: 'remix' generates imports from remix/ui and remix/ui-hmr. importSource: '@remix-run' generates imports from @remix-run/ui and @remix-run/ui-hmr. Custom import sources follow the same nested import layout.

Related Packages

  • assets - Runs loaders while compiling assets
  • node-hmr - Provides the server-side import.meta.hot runtime
  • ui - Component APIs transformed by ui-hmr

License

See LICENSE