Skip to content

Commit

Permalink
feat: add util function to generate module paths (#763)
Browse files Browse the repository at this point in the history
* feat: add util function to generate module paths

* test: move getModulePaths test to __tests__

* test: move getModulePaths test to __tests__

* feat: make getModulePaths accept array of deps

* test: simplify getModulePaths tests

* test: simplify getModulePaths tests

* chore: add getModulePaths to nodeModulesLoadingRules
  • Loading branch information
thiagobrez authored Oct 11, 2024
1 parent b041344 commit e433584
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-schools-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": minor
---

Add getModulePaths utility to generate include and exclude paths for modules in the bundler config
30 changes: 10 additions & 20 deletions packages/repack/src/rules/nodeModulesLoadingRules.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
import type { RuleSetRule } from '@rspack/core';
import { getModulePaths } from '../utils/getModulePaths';

export const NODE_MODULES_LOADING_RULES: RuleSetRule = {
type: 'javascript/auto',
test: /\.[cm]?[jt]sx?$/,
include: [/node_modules/],
exclude: [
// classic paths
/node_modules([/\\])+react[/\\]/,
/node_modules([/\\])+react-native[/\\]/,
/node_modules([/\\])+@react-native[/\\]/,
// classic paths for OOT
/node_modules([/\\])+react-native-macos[/\\]/,
/node_modules([/\\])+react-native-windows[/\\]/,
/node_modules([/\\])+react-native-tvos[/\\]/,
/node_modules([/\\])+@callstack[/\\]react-native-visionos[/\\]/,
// exotic paths (e.g. pnpm)
/node_modules(.*[/\\])+react@/,
/node_modules(.*[/\\])+react-native@/,
/node_modules(.*[/\\])+@react-native\+/,
// exotic paths for OOT
/node_modules(.*[/\\])+react-native-macos@/,
/node_modules(.*[/\\])+react-native-windows@/,
/node_modules(.*[/\\])+react-native-tvos@/,
/node_modules(.*[/\\])+@callstack\+react-native-visionos@/,
],
exclude: getModulePaths([
'react',
'react-native',
'@react-native',
'react-native-macos',
'react-native-windows',
'react-native-tvos',
'@callstack/react-native-visionos',
]),
rules: [
{
test: /\.jsx?$/,
Expand Down
27 changes: 9 additions & 18 deletions packages/repack/src/rules/reactNativeLoadingRules.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
import type { RuleSetRule } from '@rspack/core';
import { getModulePaths } from '../utils/getModulePaths';
import { REACT_NATIVE_LAZY_IMPORTS } from './lazyImports';

export const REACT_NATIVE_LOADING_RULES: RuleSetRule = {
type: 'javascript/dynamic',
test: /\.jsx?$/,
include: [
// classic paths
/node_modules([/\\])+react-native[/\\]/,
/node_modules([/\\])+@react-native[/\\]/,
// classic paths for OOT
/node_modules([/\\])+react-native-macos[/\\]/,
/node_modules([/\\])+react-native-windows[/\\]/,
/node_modules([/\\])+react-native-tvos[/\\]/,
/node_modules([/\\])+@callstack[/\\]react-native-visionos[/\\]/,
// exotic paths (e.g. pnpm)
/node_modules(.*[/\\])+react-native@/,
/node_modules(.*[/\\])+@react-native\+/,
// exotic paths for OOT
/node_modules(.*[/\\])+react-native-macos@/,
/node_modules(.*[/\\])+react-native-windows@/,
/node_modules(.*[/\\])+react-native-tvos@/,
/node_modules(.*[/\\])+@callstack\+react-native-visionos@/,
],
include: getModulePaths([
'react-native',
'@react-native',
'react-native-macos',
'react-native-windows',
'react-native-tvos',
'@callstack/react-native-visionos',
]),
use: [
{
loader: 'builtin:swc-loader',
Expand Down
47 changes: 47 additions & 0 deletions packages/repack/src/utils/__tests__/getModulePaths.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { getModulePaths } from '../getModulePaths';

describe('getModulePaths', () => {
const packages = [
'react-native',
'react-native-windows',
'react-native-macos',
'react-native-tvos',
'@callstack/react-native-visionos',
'@react-native/core',
'@babel/core',
'@types/react',
'@expo/vector-icons',
'socket.io',
];

it.each(packages)('should generate classic path - %s', (packageName) => {
const [classicPath] = getModulePaths([packageName]);

const classicTest = `node_modules/${packageName}/`;
expect(classicPath.test(classicTest)).toBe(true);
});

it.each(packages)('should generate exotic path - %s', (packageName) => {
const [_, exoticPath] = getModulePaths([packageName]);
const exoticPackageName = packageName.replace(/[/\\]/g, '+');

const exoticTestAtSymbol = `node_modules/.pnpm/${exoticPackageName}@`;
const exoticTestPlusSymbol = `node_modules/.pnpm/${exoticPackageName}+`;

expect(exoticPath.test(exoticTestAtSymbol)).toBe(true);
expect(exoticPath.test(exoticTestPlusSymbol)).toBe(true);
});

it.each(packages)('should handle backslashes - %s', (packageName) => {
const [classicPath, exoticPath] = getModulePaths([packageName]);
const exoticPackageName = packageName.replace(/[/\\]/g, '+');

const classicTestBackslash = `node_modules\\${packageName}\\`;
const exoticTestAtSymbolBackslash = `node_modules\\.pnpm\\${exoticPackageName}@`;
const exoticTestPlusSymbolBackslash = `node_modules\\.pnpm\\${exoticPackageName}+`;

expect(classicPath.test(classicTestBackslash)).toBe(true);
expect(exoticPath.test(exoticTestAtSymbolBackslash)).toBe(true);
expect(exoticPath.test(exoticTestPlusSymbolBackslash)).toBe(true);
});
});
51 changes: 51 additions & 0 deletions packages/repack/src/utils/getModulePaths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Generates regular expressions for matching module paths in both classic (npm, yarn) and exotic (pnpm) formats.
*
* In classic paths, the module names are escaped to match both forward slashes and backslashes.
* In exotic paths, the module names' forward or backward slashes are replaced with `+`.
*
* @param moduleNames The name of the modules to generate paths for.
* @returns An array of RegExp objects.
*
* @category Webpack util
*
* @example Usage in Webpack config:
* ```ts
* import * as Repack from '@callstack/repack';
*
* return {
* ...,
* module: {
* rules: [
* ...,
* include: [
* ...Repack.getModulePaths([
* 'react-native',
* '@react-native',
* 'react-native-macos',
* 'react-native-windows',
* 'react-native-tvos',
* '@callstack/react-native-visionos',
* ...
* ]),
* ],
* ]
* }
* }
* ```
*/
export function getModulePaths(moduleNames: string[]): RegExp[] {
return moduleNames.flatMap((moduleName) => {
const escapedClassic = moduleName.replace(/[/\\]/g, '[/\\\\]');
const escapedExotic = moduleName.replace(/[/\\]/g, '\\+');

const classicPath = new RegExp(
`node_modules([/\\\\])+${escapedClassic}[/\\\\]`
);
const exoticPath = new RegExp(
`node_modules(.*[/\\\\])+${escapedExotic}[@\\+]`
);

return [classicPath, exoticPath];
});
}

0 comments on commit e433584

Please sign in to comment.