Skip to content

Commit

Permalink
feat: add ESM support for generated project
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Jul 2, 2024
1 parent 693a27b commit ee3dd9c
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 99 deletions.
2 changes: 1 addition & 1 deletion packages/create-react-native-library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import prompts, { type PromptObject } from './utils/prompts';
import generateExampleApp from './utils/generateExampleApp';
import { spawn } from './utils/spawn';

const FALLBACK_BOB_VERSION = '0.20.0';
const FALLBACK_BOB_VERSION = '0.24.0';

const BINARIES = [
/(gradlew|\.(jar|keystore|png|jpg|gif))$/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
"name": "<%- project.slug -%>",
"version": "0.1.0",
"description": "<%- project.description %>",
"main": "lib/commonjs/index",
"module": "lib/module/index",
"types": "lib/typescript/src/index.d.ts",
"react-native": "src/index",
"source": "src/index",
"main": "lib/commonjs/index.cjs",
"module": "lib/module/index.mjs",
"types": "lib/typescript/src/index.d.ts",
"exports": {
".": {
"types": "./lib/typescript/src/index.d.ts",
"import": "./lib/module/index.mjs",
"require": "./lib/commonjs/index.cjs"
}
},
"files": [
"src",
"lib",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"lib": ["esnext"],
"module": "esnext",
"moduleResolution": "node",
"lib": ["ESNext"],
"module": "ESNext",
"moduleResolution": "Bundler",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
Expand All @@ -22,7 +22,7 @@
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext",
"target": "ESNext",
"verbatimModuleSyntax": true
}
}
12 changes: 11 additions & 1 deletion packages/react-native-builder-bob/babel-preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const browserslist = require('browserslist');

module.exports = function (api, options, cwd) {
const cjs = options.modules === 'commonjs';

return {
presets: [
[
Expand All @@ -24,12 +26,20 @@ module.exports = function (api, options, cwd) {
node: '18',
},
useBuiltIns: false,
modules: options.modules || false,
modules: cjs ? 'commonjs' : false,
},
],
require.resolve('@babel/preset-react'),
require.resolve('@babel/preset-typescript'),
require.resolve('@babel/preset-flow'),
],
plugins: [
[
require.resolve('./lib/babel'),
{
extension: cjs ? 'cjs' : 'mjs',
},
],
],
};
};
58 changes: 47 additions & 11 deletions packages/react-native-builder-bob/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,17 @@ yargs
? targets[0]
: undefined;

const entries: { [key: string]: string } = {
'main': target
? path.join(output, target, 'index.js')
const entries: {
[key in 'source' | 'main' | 'module' | 'types']?: string;
} = {
source: path.join(source, entryFile),
main: target
? path.join(output, target, 'index.cjs')
: path.join(source, entryFile),
'react-native': path.join(source, entryFile),
'source': path.join(source, entryFile),
};

if (targets.includes('module')) {
entries.module = path.join(output, 'module', 'index.js');
entries.module = path.join(output, 'module', 'index.mjs');
}

if (targets.includes('typescript')) {
Expand All @@ -181,9 +182,9 @@ yargs
esModuleInterop: true,
forceConsistentCasingInFileNames: true,
jsx: 'react',
lib: ['esnext'],
module: 'esnext',
moduleResolution: 'node',
lib: ['ESNext'],
module: 'ESNext',
moduleResolution: 'Bundler',
noFallthroughCasesInSwitch: true,
noImplicitReturns: true,
noImplicitUseStrict: false,
Expand All @@ -194,7 +195,7 @@ yargs
resolveJsonModule: true,
skipLibCheck: true,
strict: true,
target: 'esnext',
target: 'ESNext',
verbatimModuleSyntax: true,
},
},
Expand All @@ -214,7 +215,7 @@ yargs
];

for (const key in entries) {
const entry = entries[key];
const entry = entries[key as keyof typeof entries];

if (pkg[key] && pkg[key] !== entry) {
const { replace } = await prompts({
Expand All @@ -232,6 +233,41 @@ yargs
}
}

if (Object.values(entries).some((entry) => entry.endsWith('.ms'))) {
let replace = false;

if (pkg.exports) {
replace = (
await prompts({
type: 'confirm',
name: 'replace',
message: `Your package.json has 'exports' field set. Do you want to replace it?`,
initial: true,
})
).replace;
} else {
replace = true;
}

if (replace) {
pkg.exports = {
'.': {},
};

if (entries.types) {
pkg.exports['.'].types = entries.types;
}

if (entries.module) {
pkg.exports['.'].import = entries.module;
}

if (entries.main) {
pkg.exports['.'].require = entries.main;
}
}
}

if (pkg.scripts?.prepare && pkg.scripts.prepare !== prepare) {
const { replace } = await prompts({
type: 'confirm',
Expand Down
1 change: 0 additions & 1 deletion packages/react-native-builder-bob/src/targets/commonjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ export default async function build({
exclude,
modules: 'commonjs',
report,
field: 'main',
});
}
1 change: 0 additions & 1 deletion packages/react-native-builder-bob/src/targets/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ export default async function build({
exclude,
modules: false,
report,
field: 'module',
});
}
77 changes: 45 additions & 32 deletions packages/react-native-builder-bob/src/targets/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,43 +217,56 @@ export default async function build({
return null;
};

if ('types' in pkg) {
const typesPath = path.join(root, pkg.types);

if (!(await fs.pathExists(typesPath))) {
const generatedTypesPath = await getGeneratedTypesPath();

if (!generatedTypesPath) {
report.warn(
`Failed to detect the entry point for the generated types. Make sure you have a valid ${kleur.blue(
'source'
)} field in your ${kleur.blue('package.json')}.`
);
}

report.error(
`The ${kleur.blue('types')} field in ${kleur.blue(
'package.json'
)} points to a non-existent file: ${kleur.blue(
pkg.types
)}.\nVerify the path points to the correct file under ${kleur.blue(
path.relative(root, output)
)}${
generatedTypesPath
? ` (found ${kleur.blue(generatedTypesPath)}).`
: '.'
}`
);
const fields = [
{ name: 'types', value: pkg.types },
{ name: "exports['.'].types", value: pkg.exports?.['.']?.types },
];

if (fields.some((field) => field.value)) {
await Promise.all(
fields.map(async ({ name, value }) => {
if (!value) {
return;
}

throw new Error("Found incorrect path in 'types' field.");
}
const typesPath = path.join(root, value);

if (!(await fs.pathExists(typesPath))) {
const generatedTypesPath = await getGeneratedTypesPath();

if (!generatedTypesPath) {
report.warn(
`Failed to detect the entry point for the generated types. Make sure you have a valid ${kleur.blue(
'source'
)} field in your ${kleur.blue('package.json')}.`
);
}

report.error(
`The ${kleur.blue(name)} field in ${kleur.blue(
'package.json'
)} points to a non-existent file: ${kleur.blue(
value
)}.\nVerify the path points to the correct file under ${kleur.blue(
path.relative(root, output)
)}${
generatedTypesPath
? ` (found ${kleur.blue(generatedTypesPath)}).`
: '.'
}`
);

throw new Error(`Found incorrect path in '${name}' field.`);
}
})
);
} else {
const generatedTypesPath = await getGeneratedTypesPath();

report.warn(
`No ${kleur.blue('types')} field found in ${kleur.blue(
'package.json'
)}.\nConsider ${
`No ${kleur.blue(
fields.map((field) => field.name).join(' or ')
)} field found in ${kleur.blue('package.json')}.\nConsider ${
generatedTypesPath
? `pointing it to ${kleur.blue(generatedTypesPath)}`
: 'adding it'
Expand Down
Loading

0 comments on commit ee3dd9c

Please sign in to comment.