Skip to content

Commit

Permalink
fix: detect entry path and show in error messages (#461)
Browse files Browse the repository at this point in the history
### Summary

This adds detection of correct entry points based on the `source` field
in `package.json`. Currently it's shown in the error message when the
entries are incorrectly configured.

In future, we may automatically update the `package.json` fields to
point to the correct paths.

<img width="691" alt="image"
src="https://github.com/callstack/react-native-builder-bob/assets/1174278/3a122970-98bd-474e-bc23-ef93c871a7db">

<img width="656" alt="image"
src="https://github.com/callstack/react-native-builder-bob/assets/1174278/5b7becc5-b19f-43a3-aebe-a2e047563c7b">


### Test plan

Tested in React Navigation monorepo.
  • Loading branch information
satya164 authored Sep 14, 2023
1 parent f6225fd commit 82ad903
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 21 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,25 @@ yarn add --dev react-native-builder-bob
"module": "lib/module/index.js",
"react-native": "src/index.ts",
"types": "lib/typescript/src/index.d.ts",
"source": "src/index.ts",
"files": [
"lib/",
"src/"
"lib",
"src"
]
```

Make sure to change specify correct files according to the targets you have enabled.
Here is what each of these fields mean:

- `main`: The entry point for the commonjs build. This is used by Node - such as tests, SSR etc.
- `module`: The entry point for the ES module build. This is used by bundlers such as webpack.
- `react-native`: The entry point for the React Native apps. This is used by Metro. It's common to point to the source code here as it can make debugging easier.
- `types`: The entry point for the TypeScript definitions. This is used by TypeScript to type check the code using your library.
- `source`: The path to the source code. It is used by `react-native-builder-bob` to detect the correct output files and provide better error messages.
- `files`: The files to include in the package when publishing with `npm`.

It's usually good to point to your source code with the `react-native` field to make debugging easier. Metro already supports compiling a lot of new syntaxes including JSX, Flow and TypeScript and it will use this field if present.
Make sure to change specify correct files according to the targets you have enabled.

If you're building TypeScript definition files, also make sure that the `types` field points to a correct path. Depending on the project configuration, the path can be different for you than the example snippet (e.g. `lib/typescript/index.d.ts` if you have only the `src` directory and `rootDir` is not set).
**NOTE**: If you're building TypeScript definition files, also make sure that the `types` field points to a correct path. Depending on the project configuration, the path can be different for you than the example snippet (e.g. `lib/typescript/index.d.ts` if you have only the `src` directory and `rootDir` is not set).

1. Add the output directory to `.gitignore` and `.eslintignore`

Expand Down
1 change: 1 addition & 0 deletions packages/react-native-builder-bob/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ yargs
? path.join(output, target, 'index.js')
: path.join(source, entryFile),
'react-native': path.join(source, entryFile),
'source': path.join(source, entryFile),
};

if (targets.includes('module')) {
Expand Down
57 changes: 45 additions & 12 deletions packages/react-native-builder-bob/src/targets/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Options = Input & {
};

export default async function build({
source,
root,
output,
report,
Expand Down Expand Up @@ -175,39 +176,71 @@ export default async function build({
await fs.readFile(path.join(root, 'package.json'), 'utf-8')
);

if ('types' in pkg) {
if (!pkg.types.endsWith('.d.ts')) {
report.error(
`The ${kleur.blue('types')} field in ${kleur.blue(
'package.json'
)} doesn't point to a definition file. Verify the path points to the correct file under ${kleur.blue(
path.relative(root, output)
)}.`
);
const getGeneratedTypesPath = async () => {
if (pkg.source) {
const indexDTsName =
path.basename(pkg.source).replace(/\.(jsx?|tsx?)$/, '') + '.d.ts';

throw new Error("Found incorrect path in 'types' field.");
const potentialPaths = [
path.join(output, path.dirname(pkg.source), indexDTsName),
path.join(
output,
path.dirname(path.relative(source, path.join(root, pkg.source))),
indexDTsName
),
];

for (const potentialPath of potentialPaths) {
if (await fs.pathExists(potentialPath)) {
return path.relative(root, potentialPath);
}
}
}

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)}).`
: '.'
}`
);

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

report.warn(
`No ${kleur.blue('types')} field found in ${kleur.blue(
'package.json'
)}.\nConsider adding it so consumers can use the types.`
)}.\nConsider ${
generatedTypesPath
? `pointing it to ${kleur.blue(generatedTypesPath)}`
: 'adding it'
} so that consumers of your package can use the types.`
);
}
} else {
Expand Down
45 changes: 41 additions & 4 deletions packages/react-native-builder-bob/src/utils/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,25 @@ export default async function compile({

report.success(`Wrote files to ${kleur.blue(path.relative(root, output))}`);

const getGeneratedEntryPath = async () => {
if (pkg.source) {
const indexName =
path.basename(pkg.source).replace(/\.(jsx?|tsx?)$/, '') + '.js';

const potentialPath = path.join(
output,
path.dirname(path.relative(source, path.join(root, pkg.source))),
indexName
);

if (await fs.pathExists(potentialPath)) {
return path.relative(root, potentialPath);
}
}

return null;
};

if (field in pkg) {
try {
require.resolve(path.join(root, pkg[field]));
Expand All @@ -157,14 +176,28 @@ export default async function compile({
'code' in e &&
e.code === 'MODULE_NOT_FOUND'
) {
const generatedEntryPath = await getGeneratedEntryPath();

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

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

throw new Error(`Found incorrect path in '${field}' field.`);
Expand All @@ -173,12 +206,16 @@ export default async function compile({
throw e;
}
} else {
const generatedEntryPath = await getGeneratedEntryPath();

report.warn(
`No ${kleur.blue(field)} field found in ${kleur.blue(
'package.json'
)}. Add it to your ${kleur.blue(
'package.json'
)} so that consumers of your package can use it.`
)}. Consider ${
generatedEntryPath
? `pointing it to ${kleur.blue(generatedEntryPath)}`
: 'adding it'
} so that consumers of your package can use it.`
);
}
}

0 comments on commit 82ad903

Please sign in to comment.