Skip to content

Commit

Permalink
🏛️ build(esm): Use explicit .mjs extension for ESM, with CJS interop (#7
Browse files Browse the repository at this point in the history
… (#7262)

* build(esm): Use explicit .mjs extension for ESM, with CJS interop (#7261)

* build(esm): Use explicit .mjs extension for ESM

This ensures that Node always treats the ESM output as ESM, despite the package.json (implicit) type of commonjs. Bundlers that expect ESM, such as Next v12, no longer explode when encountering this module.

Refs #7244
Refs #7095
Refs #7088
Refs react-hook-form/resolvers#271
Refs vercel/next.js#30750

* fix(esm-interop): Import non-ESM React as default

* 7.21.3-beta.0

* update with v2 compress

* fix lint error and update packages

Co-authored-by: Daniel Stockman <5605+evocateur@users.noreply.github.com>
  • Loading branch information
bluebill1049 and evocateur committed Dec 13, 2021
1 parent f8aa875 commit 892aa0d
Show file tree
Hide file tree
Showing 55 changed files with 434 additions and 408 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/compressed-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ jobs:

steps:
- uses: actions/checkout@v2
- uses: preactjs/compressed-size-action@v1
- uses: preactjs/compressed-size-action@v2
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
40 changes: 20 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "react-hook-form",
"description": "Performant, flexible and extensible forms library for React Hooks",
"version": "7.21.2",
"version": "7.21.3-beta.0",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"module": "dist/index.esm.mjs",
"umd:main": "dist/index.umd.js",
"unpkg": "dist/index.umd.js",
"jsdelivr": "dist/index.umd.js",
"jsnext:main": "dist/index.esm.js",
"jsnext:main": "dist/index.esm.mjs",
"source": "src/index.ts",
"types": "dist/index.d.ts",
"sideEffects": true,
Expand All @@ -18,15 +18,15 @@
"exports": {
"./package.json": "./package.json",
".": {
"import": "./dist/index.esm.js",
"import": "./dist/index.esm.mjs",
"require": "./dist/index.cjs.js"
}
},
"scripts": {
"clean": "rimraf dist",
"prebuild": "yarn clean",
"build": "yarn build:modern",
"postbuild": "rimraf dist/__tests__",
"postbuild": "rimraf dist/__tests__; node ./scripts/rollup/assert-esm-exports.mjs && node ./scripts/rollup/assert-cjs-exports.cjs",
"build:modern": "rollup -c ./scripts/rollup/rollup.config.js",
"build:esm": "rollup -c ./scripts/rollup/rollup.esm.config.js",
"prettier:fix": "prettier --config .prettierrc --write \"**/*.{ts,tsx}\"",
Expand Down Expand Up @@ -67,42 +67,42 @@
"devDependencies": {
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.0.6",
"@testing-library/jest-dom": "^5.15.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/react-native": "^8.0.0",
"@testing-library/react-native": "^9.0.0",
"@types/jest": "^27.0.3",
"@types/react": "^17.0.37",
"@types/react-native": "^0.66.6",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"@types/react-native": "^0.66.8",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"@vitejs/plugin-react-refresh": "^1.3.6",
"babel-jest": "^27.4.2",
"babel-jest": "^27.4.4",
"bundlesize": "^0.18.0",
"cypress": "9.1.0",
"eslint": "^8.3.0",
"cypress": "9.1.1",
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"husky": "^7.0.4",
"jest": "^27.4.3",
"jest": "^27.4.4",
"lint-staged": "^12.1.2",
"prettier": "^2.5.0",
"prettier": "^2.5.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-native": "^0.66.3",
"react-native": "^0.66.4",
"react-test-renderer": "^17.0.1",
"rimraf": "^3.0.2",
"rollup": "^2.60.2",
"rollup": "^2.61.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-sourcemaps": "^0.6.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.31.1",
"ts-jest": "^27.0.7",
"typescript": "^4.5.2"
"ts-jest": "^27.1.1",
"typescript": "^4.5.3"
},
"resolutions": {
"react-native/@jest/create-cache-key-function": "^27.0.2"
Expand Down Expand Up @@ -135,6 +135,6 @@
"url": "https://opencollective.com/react-hook-form"
},
"engines": {
"node": ">=12.0"
"node": ">=12.22.0"
}
}
13 changes: 13 additions & 0 deletions scripts/rollup/all-exports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
"Controller",
"FormProvider",
"appendErrors",
"get",
"set",
"useController",
"useFieldArray",
"useForm",
"useFormContext",
"useFormState",
"useWatch"
]
22 changes: 22 additions & 0 deletions scripts/rollup/assert-cjs-exports.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* This file, when executed in the postbuild lifecycle, ensures that
* the CJS output is valid CJS according to the package.json spec.
*
* @see https://nodejs.org/docs/latest/api/packages.html#packages_determining_module_system
*/
/* eslint-disable @typescript-eslint/no-var-requires */
const exported = require('react-hook-form');
const assert = require('assert');
const fs = require('fs');

/**
* When this fails, fine the update one-liner in ./assert-esm-exports.mjs
*/
const expected = JSON.parse(
fs.readFileSync(
require('path').resolve(__dirname, './all-exports.json'),
'utf-8',
),
);

assert.deepStrictEqual(Object.keys(exported), expected);
22 changes: 22 additions & 0 deletions scripts/rollup/assert-esm-exports.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* This file, when executed in the postbuild lifecycle, ensures that
* the ESM output is valid ESM according to the package.json spec.
*
* @see https://nodejs.org/docs/latest/api/packages.html#packages_determining_module_system
*/
import * as exported from 'react-hook-form';
import assert from 'assert';
import fs from 'fs';

/**
* A shell one-liner to update this array when neccessary (run from root of repo):
* node -e "import('react-hook-form').then((mod) => console.log(JSON.stringify(Object.keys(mod), null, 2)))" > scripts/rollup/all-exports.json
*/
const expected = JSON.parse(
fs.readFileSync(
new URL('./all-exports.json', import.meta.url).pathname,
'utf-8',
),
);

assert.deepStrictEqual(Object.keys(exported), expected);
5 changes: 4 additions & 1 deletion scripts/rollup/createRollupConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import typescript from 'rollup-plugin-typescript2';

export function createRollupConfig(options, callback) {
const name = options.name;
const outputName = 'dist/' + [name, options.format, 'js'].join('.');
// A file with the extension ".mjs" will always be treated as ESM, even when pkg.type is "commonjs" (the default)
// https://nodejs.org/docs/latest/api/packages.html#packages_determining_module_system
const extName = options.format === 'esm' ? 'mjs' : 'js';
const outputName = 'dist/' + [name, options.format, extName].join('.');

const config = {
input: options.input,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/controller.server.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { renderToString } from 'react-dom/server';

import { Controller } from '../controller';
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/controller.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act,
fireEvent,
Expand Down
4 changes: 0 additions & 4 deletions src/__tests__/logic/focusFieldBy.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import focusFieldBy from '../../logic/focusFieldBy';
import get from '../../utils/get';

jest.mock('../../utils/isHTMLElement', () => ({
default: () => true,
}));

describe('focusFieldBy', () => {
it('should focus on the first error it encounter', () => {
const focus = jest.fn();
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/logic/getFieldValue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import getFieldValue from '../../logic/getFieldValue';
import { Field } from '../../types';

jest.mock('../../logic/getRadioValue', () => ({
__esModule: true,
default: () => ({
value: 2,
}),
}));

jest.mock('../../logic/getCheckboxValue', () => ({
__esModule: true,
default: () => ({
value: 'testValue',
}),
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/type.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';

import { Controller } from '../controller';
import {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useController.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/append.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { act, renderHook } from '@testing-library/react-hooks';

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/focus.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { act, fireEvent, render, screen } from '@testing-library/react';

import { useFieldArray } from '../../useFieldArray';
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/insert.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/move.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/prepend.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/remove.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/replace.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { act } from '@testing-library/react-hooks';

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/swap.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useFieldArray/update.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useForm.server.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { renderToString } from 'react-dom/server';

import { useForm } from '../useForm';
Expand Down
73 changes: 32 additions & 41 deletions src/__tests__/useForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down Expand Up @@ -490,52 +490,43 @@ describe('useForm', () => {
});

describe('handleChangeRef', () => {
let Component: React.FC<{
const Component = ({
name = 'test',
resolver,
mode,
rules = { required: 'required' },
}: {
name?: string;
resolver?: any;
mode?: 'onBlur' | 'onSubmit' | 'onChange';
rules?: RegisterOptions;
}>;
let methods: UseFormReturn<{ test: string }>;

beforeEach(() => {
Component = ({
name = 'test',
}) => {
const internationalMethods = useForm<{ test: string }>({
resolver,
mode,
rules = { required: 'required' },
}: {
name?: string;
resolver?: any;
mode?: 'onBlur' | 'onSubmit' | 'onChange';
rules?: RegisterOptions;
}) => {
const internationalMethods = useForm<{ test: string }>({
resolver,
mode,
});
const {
register,
handleSubmit,
formState: { errors, isValid },
} = internationalMethods;
methods = internationalMethods;

return (
<div>
<input
type="text"
{...register(name as 'test', resolver ? {} : rules)}
/>
<span role="alert">
{errors?.test?.message && errors.test.message}
</span>
<button onClick={handleSubmit(() => {})}>button</button>
<p>{isValid ? 'valid' : 'invalid'}</p>
</div>
);
};
});
});
const {
register,
handleSubmit,
formState: { errors, isValid },
} = internationalMethods;
methods = internationalMethods;

return (
<div>
<input
type="text"
{...register(name as 'test', resolver ? {} : rules)}
/>
<span role="alert">
{errors?.test?.message && errors.test.message}
</span>
<button onClick={handleSubmit(() => {})}>button</button>
<p>{isValid ? 'valid' : 'invalid'}</p>
</div>
);
};
let methods: UseFormReturn<{ test: string }>;

describe('onSubmit mode', () => {
it('should not contain error if value is valid', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useForm/clearErrors.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/useForm/formState.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import {
act as actComponent,
fireEvent,
Expand Down

0 comments on commit 892aa0d

Please sign in to comment.