Skip to content

Commit 1e1ae0b

Browse files
committed
Switch to ESM
1 parent 3ee17cc commit 1e1ae0b

37 files changed

+154
-113
lines changed

.github/workflows/lint-js-and-ruby.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ jobs:
9090
run: yarn pack -f react-on-rails.tgz
9191
- name: Lint package types
9292
# --profile because we don't care about node10
93-
# --ignore-rules CJS default export can't be resolved at the moment,
94-
# revisit in 15.0.0
95-
run: yarn run attw react-on-rails.tgz --profile node16 --ignore-rules cjs-only-exports-default
93+
# --ignore-rules Since Node 20.19.0/22.12.0, this is no longer an error
94+
run: yarn run attw react-on-rails.tgz --profile node16 --ignore-rules cjs-resolves-to-esm
9695
- name: Lint package publishing
9796
run: yarn run publint --strict react-on-rails.tgz
9897
# We only download and run Actionlint if there is any difference in GitHub Action workflows

eslint.config.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ const config = tsEslint.config([
128128
'jsx-a11y/anchor-is-valid': 'off',
129129
},
130130
},
131+
{
132+
files: ['node_package/src/**/*'],
133+
rules: {
134+
'import/extensions': ['error', 'ignorePackages'],
135+
},
136+
},
131137
{
132138
files: ['lib/generators/react_on_rails/templates/**/*'],
133139
rules: {
@@ -138,7 +144,7 @@ const config = tsEslint.config([
138144
},
139145
},
140146
{
141-
files: ['**/*.ts', '**/*.tsx'],
147+
files: ['**/*.ts', '**/*.[cm]ts', '**/*.tsx'],
142148

143149
extends: tsEslint.configs.strictTypeChecked,
144150

@@ -173,6 +179,13 @@ const config = tsEslint.config([
173179
'@typescript-eslint/restrict-template-expressions': 'off',
174180
},
175181
},
182+
{
183+
files: ['**/*.c[jt]s'],
184+
rules: {
185+
// there is a TypeScript error when importing the default export of a .cts file in a .ts file
186+
'import/prefer-default-export': 'off',
187+
},
188+
},
176189
// must be the last config in the array
177190
// https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
178191
prettierRecommended,

jest.config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
const nodeVersion = parseInt(process.version.slice(1), 10);
22

3-
module.exports = {
3+
export default {
44
preset: 'ts-jest/presets/js-with-ts',
5+
globals: {
6+
'ts-jest': {
7+
tsconfig: 'tsconfig.jest.json',
8+
},
9+
},
510
testEnvironment: 'jsdom',
611
setupFiles: ['<rootDir>/node_package/tests/jest.setup.js'],
712
// React Server Components tests are compatible with React 19

node_package/scripts/build

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
yarn run clean
6+
yarn run tsc --declaration
7+
echo '{ "type": "module" }' > node_package/lib/esm/package.json
8+
yarn run tsc -p tsconfig.cjs.json --declaration
9+
echo '{ "type": "commonjs" }' > node_package/lib/cjs/package.json

node_package/src/Authenticity.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AuthenticityHeaders } from './types/index';
1+
import type { AuthenticityHeaders } from './_types.ts';
22

33
export default {
44
authenticityToken(): string | null {

node_package/src/CallbackRegistry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { ItemRegistrationCallback } from './types';
2-
import { onPageLoaded, onPageUnloaded } from './pageLifecycle';
3-
import { getContextAndRailsContext } from './context';
1+
import { ItemRegistrationCallback } from './_types.ts';
2+
import { onPageLoaded, onPageUnloaded } from './pageLifecycle.ts';
3+
import { getContextAndRailsContext } from './context.ts';
44

55
/**
66
* Represents information about a registered item including its value,

node_package/src/ClientSideRenderer.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
/* eslint-disable max-classes-per-file */
2-
/* eslint-disable react/no-deprecated,@typescript-eslint/no-deprecated -- while we need to support React 16 */
2+
/* eslint-disable @typescript-eslint/no-deprecated -- while we need to support React 16 */
33

4-
import * as ReactDOM from 'react-dom';
54
import type { ReactElement } from 'react';
6-
import type { RailsContext, RegisteredComponent, RenderFunction, Root } from './types';
5+
import type { RailsContext, RegisteredComponent, RenderFunction, Root } from './_types.ts';
76

8-
import { getContextAndRailsContext, resetContextAndRailsContext, type Context } from './context';
9-
import createReactOutput from './createReactOutput';
10-
import { isServerRenderHash } from './isServerRenderResult';
11-
import reactHydrateOrRender from './reactHydrateOrRender';
12-
import { supportsRootApi } from './reactApis';
13-
import { debugTurbolinks } from './turbolinksUtils';
7+
import { getContextAndRailsContext, resetContextAndRailsContext, type Context } from './context.ts';
8+
import createReactOutput from './createReactOutput.ts';
9+
import { isServerRenderHash } from './isServerRenderResult.ts';
10+
import { reactHydrateOrRender } from './reactHydrateOrRender.cts';
11+
import { canHydrate, unmountComponentAtNode, supportsRootApi } from './reactApis.cts';
12+
import { debugTurbolinks } from './turbolinksUtils.ts';
1413

1514
const REACT_ON_RAILS_STORE_ATTRIBUTE = 'data-js-react-on-rails-store';
1615

@@ -101,8 +100,7 @@ class ComponentRenderer {
101100
}
102101

103102
// Hydrate if available and was server rendered
104-
// @ts-expect-error potentially present if React 18 or greater
105-
const shouldHydrate = !!(ReactDOM.hydrate || ReactDOM.hydrateRoot) && !!domNode.innerHTML;
103+
const shouldHydrate = canHydrate && !!domNode.innerHTML;
106104

107105
const reactElementOrRouterResult = createReactOutput({
108106
componentObj,
@@ -154,7 +152,7 @@ You should return a React.Component always for the client side entry point.`);
154152
}
155153

156154
try {
157-
ReactDOM.unmountComponentAtNode(domNode);
155+
unmountComponentAtNode(domNode);
158156
} catch (e: unknown) {
159157
const error = e instanceof Error ? e : new Error('Unknown error');
160158
console.info(

node_package/src/ComponentRegistry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { type RegisteredComponent, type ReactComponentOrRenderFunction } from './types';
2-
import isRenderFunction from './isRenderFunction';
3-
import CallbackRegistry from './CallbackRegistry';
1+
import { type RegisteredComponent, type ReactComponentOrRenderFunction } from './_types.ts';
2+
import isRenderFunction from './isRenderFunction.ts';
3+
import CallbackRegistry from './CallbackRegistry.ts';
44

55
const componentRegistry = new CallbackRegistry<RegisteredComponent>('component');
66

node_package/src/RSCClientRoot.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import * as React from 'react';
44
import * as ReactDOMClient from 'react-dom/client';
55
import { createFromReadableStream } from 'react-on-rails-rsc/client';
6-
import { fetch } from './utils';
7-
import transformRSCStreamAndReplayConsoleLogs from './transformRSCStreamAndReplayConsoleLogs';
8-
import { RailsContext, RenderFunction } from './types';
6+
import { fetch } from './utils.ts';
7+
import transformRSCStreamAndReplayConsoleLogs from './transformRSCStreamAndReplayConsoleLogs.ts';
8+
import { RailsContext, RenderFunction } from './_types.ts';
99

1010
const { use } = React;
1111

node_package/src/ReactOnRails.client.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { ReactElement } from 'react';
2-
import * as ClientStartup from './clientStartup';
3-
import { renderOrHydrateComponent, hydrateStore } from './ClientSideRenderer';
4-
import ComponentRegistry from './ComponentRegistry';
5-
import StoreRegistry from './StoreRegistry';
6-
import buildConsoleReplay from './buildConsoleReplay';
7-
import createReactOutput from './createReactOutput';
8-
import Authenticity from './Authenticity';
9-
import context from './context';
2+
import * as ClientStartup from './clientStartup.ts';
3+
import { renderOrHydrateComponent, hydrateStore } from './ClientSideRenderer.ts';
4+
import ComponentRegistry from './ComponentRegistry.ts';
5+
import StoreRegistry from './StoreRegistry.ts';
6+
import buildConsoleReplay from './buildConsoleReplay.ts';
7+
import createReactOutput from './createReactOutput.ts';
8+
import Authenticity from './Authenticity.ts';
9+
import context from './context.ts';
1010
import type {
1111
RegisteredComponent,
1212
RenderResult,
@@ -16,8 +16,8 @@ import type {
1616
Store,
1717
StoreGenerator,
1818
ReactOnRailsOptions,
19-
} from './types';
20-
import reactHydrateOrRender from './reactHydrateOrRender';
19+
} from './_types.ts';
20+
import { reactHydrateOrRender } from './reactHydrateOrRender.cts';
2121

2222
const ctx = context();
2323

@@ -203,5 +203,5 @@ ctx.ReactOnRails.resetOptions();
203203

204204
ClientStartup.clientStartup(ctx);
205205

206-
export * from './types';
206+
export * from './_types.ts';
207207
export default ctx.ReactOnRails;

0 commit comments

Comments
 (0)