Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Worklets): JS code duplication #6921

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2f8b9c4
feat: stub of node module react-native-worklets
tjzel Dec 11, 2024
fcfda4f
feat: preliminary use of react-native-worklets in reanimated
tjzel Dec 11, 2024
a9b6af2
chore: fix CMakeLists
tjzel Dec 12, 2024
96b76d7
Merge branch 'main' into @tjzel/worklets/node-module-with-rea-support
tjzel Dec 12, 2024
3ee4d4f
chore: add explanatory comments
tjzel Dec 17, 2024
1f40ace
feat: add linting to react-native-worklets
tjzel Dec 17, 2024
7fccc99
chore: add missing dependency
tjzel Dec 17, 2024
661706a
chore: add external-worklets-example
tjzel Dec 12, 2024
b127bea
chore: fix FabricExample occurences
tjzel Dec 17, 2024
a507fdc
chore: update github actions
tjzel Dec 17, 2024
afd030d
chore: fix CI
tjzel Dec 17, 2024
2634199
chore: remove excessive changes
tjzel Dec 12, 2024
64aea46
chore: remove external worklets
tjzel Jan 20, 2025
3701183
chore: cleanup
tjzel Jan 20, 2025
ceee2f7
chore: draft duplication
tjzel Dec 17, 2024
62c9488
chore: cleanup
tjzel Jan 21, 2025
50d3f00
chore: improve react-native-worklets detection script
tjzel Jan 21, 2025
7e75fb3
refactor: move ReanimatedVersion to Reanimated
tjzel Jan 21, 2025
f1aa4be
refactor: duplicatable code
tjzel Jan 22, 2025
972d143
chore: fix filename in script
tjzel Jan 22, 2025
88e38c0
Merge branch 'main' into @tjzel/worklets/restructure-worklets-source-…
tjzel Jan 23, 2025
08ad6ab
chore: cleanup
tjzel Jan 23, 2025
6a35149
chore: cleanup
tjzel Jan 23, 2025
45a4c27
Merge branch 'main' into @tjzel/worklets/restructure-worklets-source-…
tjzel Jan 23, 2025
1bcb1a9
Merge remote-tracking branch 'origin/@tjzel/worklets/restructure-work…
tjzel Jan 24, 2025
077304b
chore: fix CI issues
tjzel Jan 24, 2025
e492782
Merge branch '@tjzel/worklets/duplicate-reanimated-code' into @tjzel/…
tjzel Jan 24, 2025
f70c622
chore: cleanup
tjzel Jan 24, 2025
4cb0b45
chore: fix ts error
tjzel Jan 24, 2025
6ee2b7b
chore: aggregate commit
tjzel Jan 29, 2025
6fd9490
Merge branch 'main' into @tjzel/worklets/duplicate-javascript
tjzel Jan 29, 2025
201d42c
chore: cleanup
tjzel Jan 29, 2025
e9ad506
chore: try adjust gitattributes
tjzel Jan 29, 2025
383beed
chore: fix ci
tjzel Jan 29, 2025
428d6ed
chore: remove debugging code
tjzel Jan 29, 2025
93e8dfb
chore: fix importing react-native-worklets
tjzel Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.yarn/** linguist-vendored=true
/.yarn/releases/* binary=true
/.yarn/plugins/**/* binary=true
/packages/eslint-plugin-reanimated/index.js linguist-generated=true
/packages/eslint-plugin-reanimated/types linguist-generated=true
5 changes: 0 additions & 5 deletions .github/workflows/example-android-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,6 @@ jobs:
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

- name: Use external worklets
if: ${{ inputs.use-external-worklets == 'true' }}
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

Comment on lines -72 to -76
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how things keep duplicating when I rebase 😭

- name: Build app
working-directory: ${{ env.WORKING_DIRECTORY }}/android
run: ./gradlew assembleDebug --build-cache -PreactNativeArchitectures=arm64-v8a
5 changes: 0 additions & 5 deletions .github/workflows/example-macos-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ jobs:
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

- name: Use external worklets
if: ${{ inputs.use-external-worklets == 'true' }}
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

- name: Install Pods
working-directory: ${{ env.WORKING_DIRECTORY }}/macos
run: |
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/example-tvos-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,6 @@ jobs:
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

- name: Use external worklets
if: ${{ inputs.use-external-worklets == 'true' }}
working-directory: ${{ env.COMMON_APP_DIR }}
run: yarn add react-native-worklets@workspace:"*"

- name: Install Pods
working-directory: ${{ env.WORKING_DIRECTORY }}/ios
run: |
Expand Down
33 changes: 32 additions & 1 deletion apps/common-app/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
import App from '@/App';
/* eslint-disable no-var */
/* eslint-disable no-inner-declarations */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable no-underscore-dangle */

// This detection mechanism is necessary for the time being for dynamic
// resolution of worklets. `react-native-worklets` is present in monorepo's
// node_modules therefore allowed to be imported though it's not a dependency.
let hasExternalWorklets = false;
try {
const packageJson = require('./package.json') as Record<
string,
Record<string, unknown>
>;
hasExternalWorklets =
packageJson?.dependencies?.['react-native-worklets'] !== undefined ||
packageJson?.devDependencies?.['react-native-worklets'] !== undefined;
} catch (_e) {
// Do nothing.
}

declare global {
var __DISALLOW_WORKLETS_IMPORT: boolean | undefined;
}

globalThis.__DISALLOW_WORKLETS_IMPORT = !hasExternalWorklets;

// Has to be imported dynamically to inject __DISALLOW_WORKLETS_IMPORT before
// any other code is executed.
const App = require('@/App').default;

export default App;
47 changes: 47 additions & 0 deletions packages/eslint-plugin-reanimated/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/eslint-plugin-reanimated/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { TSESLint } from '@typescript-eslint/utils';
import noAnimatedStyleToNonAnimatedComponent from './noAnimatedStyleToNonAnimatedComponent';
import useReanimatedError from './useReanimatedError';
import useWorkletsResolver from './useWorkletsResolver';

export const rules = {
'animated-style-non-animated-component':
noAnimatedStyleToNonAnimatedComponent,
'use-reanimated-error': useReanimatedError,
'use-worklets-resolver': useWorkletsResolver,
} satisfies Record<string, TSESLint.RuleModule<string, Array<unknown>>>;
41 changes: 41 additions & 0 deletions packages/eslint-plugin-reanimated/src/useWorkletsResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';

const rule: TSESLint.RuleModule<'useWorkletsResolver', []> = {
create: function (context) {
return {
ImportDeclaration(node: TSESTree.ImportDeclaration) {
const workletsRegex = /\/worklets[/.*]?/;
if (node.source.value.match(workletsRegex)) {
const replacement = node.source.value.replace(
workletsRegex,
'/WorkletsResolver'
);

context.report({
node,
messageId: 'useWorkletsResolver',
fix: function (fixer) {
return fixer.replaceText(node.source, `'${replacement}'`);
},
});
}
},
};
},
meta: {
docs: {
recommended: 'recommended',
description:
"Warns when `react-native-reanimated` doesn't use `WorkletsResolver` to import worklets' files`.",
},
messages: {
useWorkletsResolver: "Import worklets' files via WorkletsResolver.",
},
type: 'suggestion',
schema: [],
fixable: 'code',
},
defaultOptions: [],
};

export default rule;
5 changes: 5 additions & 0 deletions packages/eslint-plugin-reanimated/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ export declare const rules: {
[],
TSESLint.RuleListener
>;
'use-worklets-resolver': TSESLint.RuleModule<
'useWorkletsResolver',
[],
TSESLint.RuleListener
>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { TSESLint } from '@typescript-eslint/utils';
declare const rule: TSESLint.RuleModule<'useWorkletsResolver', []>;
export default rule;
7 changes: 7 additions & 0 deletions packages/react-native-reanimated/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ module.exports = {
overrides: [
{
files: ['./src/**/*.ts', './src/**/*.tsx'],
excludedFiles: [
'./src/worklets/**/*.ts',
'./src/worklets/**/*.tsx',
'./src/WorkletsResolver/**/*.ts',
'./src/WorkletsResolver/**/*.tsx',
],
plugins: ['reanimated'],
rules: {
'reanimated/use-reanimated-error': 'error',
'reanimated/use-worklets-resolver': 'error',
},
},
],
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-reanimated/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,4 @@ apple/worklets
Common/cpp/worklets
android/src/worklets
android/src/main/cpp/worklets
src/worklets
2 changes: 1 addition & 1 deletion packages/react-native-reanimated/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"format:android:cpp": "find android/src -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
"format:android:cmake": "find ./android -type d \\( -name build -o -name .cxx \\) -prune -o -type f -name 'CMakeLists.txt' -print | xargs ./scripts/format-cmake.sh",
"format:common": "find Common -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
"find-unused-code:js": "yarn ts-prune --ignore \"index|.web.\" --error",
"find-unused-code:js": "yarn ts-prune --ignore \"index|.web.|src/worklets\" --error",
"type:check": "yarn type:check:src && yarn type:check:plugin && yarn type:check:app && ./scripts/test-ts.sh __typetests__/common",
"type:check:src": "yarn tsc --noEmit",
"type:check:plugin": "cd plugin && yarn type:check:src",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,28 @@ copy_files_recursively() {
done
}

WORKLETS_DIR="../react-native-worklets"

if [ ! -d "$WORKLETS_DIR" ]; then
echo "Please run this script from react-native-reanimated package"
exit 1
fi

# Worklets TypeScript files
# Note that we only duplicate "worklets" subdirectory
copy_files_recursively "src/worklets" "$WORKLETS_DIR/src/worklets"

# Worklets iOS files
copy_files_recursively "apple/worklets" "../react-native-worklets/apple/worklets"
copy_files_recursively "apple/worklets" "$WORKLETS_DIR/apple/worklets"

# Worklets Android files
# Note that we don't duplicate "android/src/main"
copy_files_recursively "android/src/worklets" "../react-native-worklets/android/src/worklets"
copy_files_recursively "android/src/worklets" "$WORKLETS_DIR/android/src/worklets"

# Worklets Android-specific cpp files
copy_files_recursively "android/src/main/cpp/worklets" "../react-native-worklets/android/src/main/cpp/worklets"
copy_files_recursively "android/src/main/cpp/worklets" "$WORKLETS_DIR/android/src/main/cpp/worklets"

# Worklets Common cpp files
copy_files_recursively "Common/cpp/worklets" "../react-native-worklets/Common/cpp/worklets"
copy_files_recursively "Common/cpp/worklets" "$WORKLETS_DIR/Common/cpp/worklets"

echo "Done duplicating Worklets in Reanimated"
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
'use strict';
import type React from 'react';
import type {
Value3D,
ValueRotation,
ShareableRef,
LayoutAnimationBatchItem,
IReanimatedModule,
IWorkletsModule,
WorkletFunction,
ShadowNodeWrapper,
StyleProps,
Value3D,
ValueRotation,
} from '../commonTypes';
import { checkCppVersion } from '../platform-specific/checkCppVersion';
import { jsVersion } from '../platform-specific/jsVersion';
import { isFabric, isWeb } from '../PlatformChecker';
import type React from 'react';
import { getShadowNodeWrapperFromRef } from '../fabricUtils';
import { ReanimatedTurboModule } from '../specs';
import { ReanimatedError } from '../errors';
import { WorkletsModule } from '../worklets';
import type { ReanimatedModuleProxy } from './reanimatedModuleProxy';
import type {
NormalizedCSSTransitionConfig,
NormalizedSingleCSSAnimationConfig,
NormalizedSingleCSSAnimationSettings,
} from '../css/platform/native';
import { ReanimatedError } from '../errors';
import { getShadowNodeWrapperFromRef } from '../fabricUtils';
import { checkCppVersion } from '../platform-specific/checkCppVersion';
import { jsVersion } from '../platform-specific/jsVersion';
import { isFabric, shouldBeUseWeb } from '../PlatformChecker';
import { ReanimatedTurboModule } from '../specs';
import type {
ShareableRef,
WorkletFunction,
IWorkletsModule,
} from '../WorkletsResolver';
import { WorkletsModule } from '../WorkletsResolver';
import type {
IReanimatedModule,
ReanimatedModuleProxy,
} from './reanimatedModuleProxy';

const IS_WEB = isWeb();
const IS_WEB = shouldBeUseWeb();

export function createNativeReanimatedModule(): IReanimatedModule {
return new NativeReanimatedModule();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
'use strict';

export { ReanimatedModule } from './reanimatedModuleInstance';
export type { ReanimatedModuleProxy } from './reanimatedModuleProxy';
export type {
IReanimatedModule,
ReanimatedModuleProxy,
} from './reanimatedModuleProxy';
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
// this file was created to prevent NativeReanimated from being included in the web bundle
import { createJSReanimatedModule } from './js-reanimated';
export const ReanimatedModule = createJSReanimatedModule();
export type {
IReanimatedModule,
ReanimatedModuleProxy,
} from './reanimatedModuleProxy';
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
'use strict';
import {
isChromeDebugger,
isJest,
isWeb,
isWindowAvailable,
} from '../../PlatformChecker';
import { SensorType } from '../../commonTypes';
import type {
IReanimatedModule,
IWorkletsModule,
ShadowNodeWrapper,
ShareableRef,
StyleProps,
Value3D,
ValueRotation,
WorkletFunction,
} from '../../commonTypes';
import type { WebSensor } from './WebSensor';
import { logger } from '../../logger';
import { ReanimatedError } from '../../errors';
import { WorkletsModule } from '../../worklets';
import { SensorType } from '../../commonTypes';
import type {
NormalizedCSSTransitionConfig,
NormalizedSingleCSSAnimationConfig,
NormalizedSingleCSSAnimationSettings,
} from '../../css/platform/native';
import { ReanimatedError } from '../../errors';
import { logger } from '../../logger';
import {
isChromeDebugger,
isJest,
isWeb,
isWindowAvailable,
} from '../../PlatformChecker';
import type {
IWorkletsModule,
ShareableRef,
WorkletFunction,
} from '../../WorkletsResolver';
import { WorkletsModule } from '../../WorkletsResolver';
import type { IReanimatedModule } from '../reanimatedModuleProxy';
import type { WebSensor } from './WebSensor';

export function createJSReanimatedModule(): IReanimatedModule {
return new JSReanimated();
Expand Down
Loading
Loading