Skip to content

Commit

Permalink
Fix types and exports of the package (#197)
Browse files Browse the repository at this point in the history
* fix: types in the main export

* fix: issue with parcel exports/types

* fix: remove required files from gitignore

* fix: paths in the parcel package.json stub

* chore: add a changeset

* fix: issue with having to access the default export with ".default" when using node16 (cjs) resolution strategy

* chore: switch main export to cjs version

* fix: export re-assignment

* chore: remove unnecessary node16 interoperability

* docs: update changelog with more details

* fix: remove CJS compatibility layer

* fix: revert "main" fields to point to UMD bundle, instead of CJS
  • Loading branch information
MilanKovacic authored Jan 4, 2024
1 parent f22690d commit 1141959
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 10 deletions.
11 changes: 11 additions & 0 deletions .changeset/strong-otters-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"single-spa-react": major
---

### Fixed

- Enhanced compatibility with various bundlers and TypeScript `moduleResolution` strategies. The package's export patterns have been refined to address issues previously encountered with different bundling tools, ensuring more consistent and reliable integration across diverse build environments. Additionally, TypeScript type definitions have been improved, enhancing type safety and developer experience in varied TypeScript setups.

### BREAKING CHANGES

- The changes in export patterns / types may require updates in how projects import from `single-spa-react/*`.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ node_modules/
.DS_Store
lib/
yarn-error.log
coverage
parcel/
coverage
25 changes: 18 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,39 @@
"exports": {
"./package.json": "./package.json",
".": {
"import": "./lib/esm/single-spa-react.js",
"require": "./lib/cjs/single-spa-react.cjs"
"import": {
"types": "./types/single-spa-react.d.ts",
"default": "./lib/esm/single-spa-react.js"
},
"require": {
"types": "./types/single-spa-react.d.cts",
"default": "./lib/cjs/single-spa-react.cjs"
}
},
"./parcel": {
"import": "./lib/esm/parcel.js",
"require": "./lib/cjs/parcel.cjs"
"import": {
"types": "./types/parcel/index.d.ts",
"default": "./lib/esm/parcel.js"
},
"require": {
"types": "./types/parcel/index.d.cts",
"default": "./lib/cjs/parcel.cjs"
}
}
},
"types": "types/single-spa-react.d.cts",
"files": [
"lib",
"parcel",
"types/single-spa-react.d.ts",
"types",
"README.md"
],
"tsd": {
"directory": "src"
},
"types": "types/single-spa-react.d.ts",
"scripts": {
"build": "concurrently pnpm:build:*",
"build:rollup": "rollup -c",
"build:types": "rimraf parcel && copyfiles -f types/parcel/index.d.ts ./parcel",
"lint": "eslint src",
"test": "concurrently pnpm:test:*",
"test:browser": "cross-env BABEL_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --coverage",
Expand Down
20 changes: 20 additions & 0 deletions parcel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Parcel Folder

## Overview
This folder contains a `package.json` stub that redirects module resolutions, following the `package-json-redirects` strategy.

## Why It's Here
Serves as a compatibility layer for Node 10, which does not support the `exports` field in `package.json`. A separate `package.json` with `main` and `types` fields directs Node 10's resolution strategy to the appropriate files.

```json
{
"main": "./lib/cjs/parcel.cjs",
"types": "./types/parcel/index.d.cts"
}
```

## How It Works
When Node 10 attempts to import from this folder, it consults the `main` and `types` fields in `package.json` to locate the actual implementation and types files. This facilitates keeping those files in separate subfolders while making them accessible to older Node versions.

## Reference
For more detailed information and examples, see [this GitHub repository](https://github.com/andrewbranch/example-subpath-exports-ts-compat/tree/main/examples/node_modules/package-json-redirects).
4 changes: 4 additions & 0 deletions parcel/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "../lib/umd/parcel.js",
"types": "../types/parcel/index.d.cts"
}
4 changes: 3 additions & 1 deletion src/single-spa-react.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const defaultOpts = {
unmountResolves: {},
};

export default function singleSpaReact(userOpts) {
function singleSpaReact(userOpts) {
if (typeof userOpts !== "object") {
throw new Error(`single-spa-react requires a configuration object`);
}
Expand Down Expand Up @@ -375,3 +375,5 @@ function createSingleSpaRoot(opts) {

return SingleSpaRoot;
}

export default singleSpaReact;
36 changes: 36 additions & 0 deletions types/parcel/index.d.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react";
import {
ParcelConfig,
ParcelProps,
Parcel as SingleSpaParcel,
} from "single-spa";

interface ParcelCompProps<ExtraProps = {}> {
config: ParcelConfig<ExtraProps>;
mountParcel?: (
parcelConfig: ParcelConfig,
parcelProps: ParcelProps & ExtraProps
) => SingleSpaParcel;
wrapWith?: string;
wrapStyle?: React.CSSProperties;
wrapClassName?: string;
appendTo?: HTMLElement;
parcelDidMount?: () => any;
handleError?: (err: Error) => any;
[extraProp: string]: any;
}

interface ParcelState {
hasError: boolean;
}

declare class Parcel<ExtraProps = {}> extends React.Component<
ParcelCompProps<ExtraProps>,
ParcelState
> {}

export = Parcel;

declare namespace Parcel {
export { ParcelCompProps, ParcelState };
}
63 changes: 63 additions & 0 deletions types/single-spa-react.d.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from "react";
import { AppProps, CustomProps, LifeCycleFn } from "single-spa";

declare const SingleSpaContext: React.Context<CustomProps & AppProps>;

type DeprecatedRenderTypes =
| "createBlockingRoot"
| "unstable_createRoot"
| "unstable_createBlockingRoot";

type LegacyRenderType = "hydrate" | "render";

type RenderType = "createRoot" | "hydrateRoot" | LegacyRenderType;

interface SingleSpaReactOpts<RootComponentProps> {
React: any;
ReactDOM?: {
[T in LegacyRenderType]?: any;
};
ReactDOMClient?: {
[T in RenderType]?: any;
};
rootComponent?:
| React.ComponentClass<RootComponentProps, any>
| React.FunctionComponent<RootComponentProps>;
loadRootComponent?: (
props?: RootComponentProps
) => Promise<React.ElementType<typeof props>>;
errorBoundary?: (
err: Error,
errInfo: React.ErrorInfo,
props: RootComponentProps
) => React.ReactElement;
errorBoundaryClass?: React.ComponentClass<RootComponentProps>;
parcelCanUpdate?: boolean;
suppressComponentDidCatchWarning?: boolean;
domElementGetter?: (props: RootComponentProps) => HTMLElement;
renderType?: RenderType | (() => RenderType);
}

interface ReactAppOrParcel<ExtraProps> {
bootstrap: LifeCycleFn<ExtraProps>;
mount: LifeCycleFn<ExtraProps>;
unmount: LifeCycleFn<ExtraProps>;
update?: LifeCycleFn<ExtraProps>;
}

declare function singleSpaReact<ExtraProps = {}>(
opts: SingleSpaReactOpts<ExtraProps & AppProps>
): ReactAppOrParcel<ExtraProps>;

export = singleSpaReact;

declare namespace singleSpaReact {
export {
SingleSpaContext,
DeprecatedRenderTypes,
LegacyRenderType,
RenderType,
SingleSpaReactOpts,
ReactAppOrParcel,
};
}

0 comments on commit 1141959

Please sign in to comment.