Skip to content

Commit

Permalink
feat(webapis/polyfills): introduce @react-native-webapis/polyfills
Browse files Browse the repository at this point in the history
  • Loading branch information
tido64 committed Aug 3, 2023
1 parent 7e17bac commit c70ed71
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .changeset/silver-mayflies-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
/incubator/*/bin/
/incubator/*/dist/
/incubator/*/lib/
/incubator/@react-native-webapis/*/lib/
/packages/*/*.LICENSE.txt
/packages/*/*/rnx-build/
/packages/*/bin/
Expand Down
35 changes: 35 additions & 0 deletions incubator/@react-native-webapis/polyfills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- We recommend an empty change log entry for a new package: `yarn change --empty` -->

# @react-native-webapis/polyfills

[![Build](https://github.com/microsoft/rnx-kit/actions/workflows/build.yml/badge.svg)](https://github.com/microsoft/rnx-kit/actions/workflows/build.yml)
[![npm version](https://img.shields.io/npm/v/@react-native-webapis/polyfills)](https://www.npmjs.com/package/@react-native-webapis/polyfills)

🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧

### THIS TOOL IS EXPERIMENTAL — USE WITH CAUTION

🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧

This is a sample folder to use as base for generating new packages for
`rnx-kit`.

## Motivation

We want new packages to follow an existing set of patterns and guidelines; via
this package, we can enforce easily allow new folders to stick to at least a
common starting point.

## Installation

```sh
yarn add @react-native-webapis/polyfills --dev
```

or if you're using npm

```sh
npm add --save-dev @react-native-webapis/polyfills
```

## Usage
74 changes: 74 additions & 0 deletions incubator/@react-native-webapis/polyfills/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"private": true,
"name": "@react-native-webapis/polyfills",
"version": "0.0.1",
"description": "EXPERIMENTAL - USE WITH CAUTION - New package called polyfills",
"homepage": "https://github.com/microsoft/rnx-kit/tree/main/incubator/@react-native-webapis/polyfills#readme",
"license": "MIT",
"author": {
"name": "Microsoft Open Source",
"email": "microsoftopensource@users.noreply.github.com"
},
"files": [
"lib/*"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/rnx-kit",
"directory": "incubator/@react-native-webapis/polyfills"
},
"engines": {
"node": ">=14.15"
},
"scripts": {
"build": "rnx-kit-scripts build",
"format": "rnx-kit-scripts format",
"lint": "rnx-kit-scripts lint",
"test": "rnx-kit-scripts test"
},
"dependencies": {
"@rnx-kit/console": "^1.0.0",
"@rnx-kit/tools-node": "^2.0.0",
"@rnx-kit/tools-react-native": "^1.3.1"
},
"peerDependencies": {
"@react-native/js-polyfills": "*",
"react-native": ">=0.71.0"
},
"peerDependenciesMeta": {
"@react-native/js-polyfills": {
"optional": true
}
},
"devDependencies": {
"@rnx-kit/scripts": "*",
"eslint": "^8.0.0",
"jest": "^29.2.1",
"metro-config": "^0.73.7",
"prettier": "^3.0.0",
"typescript": "^5.0.0"
},
"eslintConfig": {
"extends": "@rnx-kit/eslint-config"
},
"jest": {
"preset": "@rnx-kit/scripts"
},
"rnx-kit": {
"alignDeps": {
"presets": [
"microsoft/react-native",
"@rnx-kit/scripts/align-deps-preset.js"
],
"requirements": [
"react-native@0.71"
],
"capabilities": [
"metro-config"
]
}
},
"experimental": true
}
34 changes: 34 additions & 0 deletions incubator/@react-native-webapis/polyfills/src/defaultPolyfills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { error } from "@rnx-kit/console";
import { getAvailablePlatforms } from "@rnx-kit/tools-react-native";
import type { Context } from "./types";

function getDefaultPolyfillsPath({
platform,
projectRoot,
}: Context): string | null {
const options = { paths: [projectRoot] };

try {
return require.resolve("@react-native/js-polyfills", options);
} catch (_) {
// `@react-native/js-polyfills` is available from 0.72+
}

const platforms = getAvailablePlatforms(projectRoot);
const reactNativePath = platforms[platform || "ios"] || "react-native";

try {
return require.resolve(`${reactNativePath}/rn-get-polyfills`, options);
} catch (_) {
error(
`Could not find polyfills for '${platform}' — if this is expected, you can ignore this error message`
);
}

return null;
}

export function getDefaultPolyfills(context: Context): string[] {
const defaultPolyfillsPath = getDefaultPolyfillsPath(context);
return defaultPolyfillsPath ? require(defaultPolyfillsPath)() : [];
}
53 changes: 53 additions & 0 deletions incubator/@react-native-webapis/polyfills/src/dependency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { error } from "@rnx-kit/console";
import { readPackage } from "@rnx-kit/tools-node";
import * as path from "path";
import type { Context } from "./types";

function getDependencies({ projectRoot }: Context): string[] {
const manifest = readPackage(projectRoot);

const dependencies = new Set<string>();
for (const section of ["dependencies", "devDependencies"] as const) {
const names = manifest[section];
if (names) {
Object.keys(names).forEach((name) => dependencies.add(name));
}
}

return Array.from(dependencies);
}

function isValidPath(p: string): boolean {
return (
Boolean(p) &&
!p.startsWith("..") &&
!p.startsWith("/") &&
!/^[A-Za-z]:/.test(p)
);
}

export function getDependencyPolyfills(context: Context): string[] {
const polyfills: string[] = [];

const options = { paths: [context.projectRoot] };
const dependencies = getDependencies(context);

for (const name of dependencies) {
try {
const config = require.resolve(`${name}/react-native.config.js`, options);
const polyfill = require(config).dependency?.api?.polyfill;
if (typeof polyfill === "string") {
if (!isValidPath(polyfill)) {
error(`${name}: invalid polyfill path: ${polyfill}`);
continue;
}

polyfills.push(path.resolve(path.dirname(config), polyfill));
}
} catch (_) {
// ignore
}
}

return polyfills;
}
12 changes: 12 additions & 0 deletions incubator/@react-native-webapis/polyfills/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getDefaultPolyfills } from "./defaultPolyfills";
import { getDependencyPolyfills } from "./dependency";
import type { GetPolyfills } from "./types";

export const getPolyfills: GetPolyfills = ({ platform }) => {
const context = { platform, projectRoot: process.cwd() };
const polyfills = getDefaultPolyfills(context);
const dependencyPolyfills = getDependencyPolyfills(context);
return polyfills.concat(dependencyPolyfills);
};

export default getPolyfills;
8 changes: 8 additions & 0 deletions incubator/@react-native-webapis/polyfills/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { ConfigT } from "metro-config";

export type Context = {
platform: string | null;
projectRoot: string;
};

export type GetPolyfills = ConfigT["serializer"]["getPolyfills"];
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getDefaultPolyfills } from "../src/defaultPolyfills";

describe("getDefaultPolyfills", () => {
const context = {
platform: "ios",
projectRoot: process.cwd(),
};

it("should return default polyfills", () => {
const defaultPolyfills = getDefaultPolyfills(context).sort();
expect(defaultPolyfills).toEqual([
expect.stringMatching(/[/\\]@react-native[/\\]polyfills[/\\]Object.es8.js$/),
expect.stringMatching(/[/\\]@react-native[/\\]polyfills[/\\]console.js$/),
expect.stringMatching(/[/\\]@react-native[/\\]polyfills[/\\]error-guard.js$/),
]);
});
});
4 changes: 4 additions & 0 deletions incubator/@react-native-webapis/polyfills/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@rnx-kit/scripts/tsconfig-shared.json",
"include": ["src"]
}
22 changes: 22 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3180,6 +3180,28 @@ __metadata:
languageName: node
linkType: hard

"@react-native-webapis/polyfills@workspace:incubator/@react-native-webapis/polyfills":
version: 0.0.0-use.local
resolution: "@react-native-webapis/polyfills@workspace:incubator/@react-native-webapis/polyfills"
dependencies:
"@rnx-kit/console": ^1.0.0
"@rnx-kit/scripts": "*"
"@rnx-kit/tools-node": ^2.0.0
"@rnx-kit/tools-react-native": ^1.3.1
eslint: ^8.0.0
jest: ^29.2.1
metro-config: ^0.73.7
prettier: ^3.0.0
typescript: ^5.0.0
peerDependencies:
"@react-native/js-polyfills": "*"
react-native: ">=0.71.0"
peerDependenciesMeta:
"@react-native/js-polyfills":
optional: true
languageName: unknown
linkType: soft

"@react-native-webapis/types@workspace:incubator/@react-native-webapis/types":
version: 0.0.0-use.local
resolution: "@react-native-webapis/types@workspace:incubator/@react-native-webapis/types"
Expand Down

0 comments on commit c70ed71

Please sign in to comment.