# Migrating [Universal Modules][universal-modules] to TypeScript - [Change Import](#change-import) - [Testing](#testing) - [Add the tests to CI](#add-the-tests-to-ci) - [Move native `dependencies` to `peerDependencies`](#move-native--dependencies--to--peerdependencies-) - [Add module scripts](#add-module-scripts) - [Generate a `tsconfig.json` file with `expo-module-scripts`](#generate-a--tsconfigjson--file-with--expo-module-scripts-) - [Various Other Changes](#various-other-changes) ## Change Import To optimize our libraries for _dead code elimination_ we should migrate our exports to be imported as such: ```diff - import { FileSystem } from 'expo-file-system'; + import * as FileSystem from 'expo-file-system'; ``` Ideally we would make the main entry-point of a module be a file named like the module like `build/FileSystem.js` **`package.json`** ```diff - "main": "index.js", + "main": "build/.js", + "types": "build/.d.ts", ``` To migrate from libraries using different imports, we should add a deprecation notice. > A lot of libraries are just import from Expo, in these cases we can just the deprecation. Ensure you change all imports across `packages/`, `apps/`, and `docs/`. **`src/index.ts`** ```ts import * as FileSystem from './FileSystem'; export * from './FileSystem'; let wasImportWarningShown = false; // @ts-ignore: Temporarily define an export named "FileSystem" for legacy compatibility Object.defineProperty(exports, 'FileSystem', { get() { if (!wasImportWarningShown) { console.warn( `The syntax "import { FileSystem } from 'expo-file-system'" is deprecated. Use "import * as FileSystem from 'expo-file-system'" or import named exports instead. Support for the old syntax will be removed in SDK 34.` ); wasImportWarningShown = true; } return FileSystem; }, }); ``` Then eventually remove the index in favor of the named file. (`src/FileSystem.ts`) ## Testing Migration should include the addition of a `src/__tests__` which can be run with `yarn test` in the root directory of the package. 1. If the package is using the old structure of `test/` for utilities, they should migrate to using `jest-expo`. **`src/__tests__/-test.ts`** ```diff - import { mockPlatformWeb } from '../../test/mocking'; + import { mockPlatformWeb } from 'jest-expo'; ``` 2. Add a jest object to the `package.json` **`package.json`** ```js "jest": { "preset": "expo-module-scripts" }, ``` 3. Run `yarn test` to run the tests. ### Add the tests to CI In the root `.circleci/config.yaml` add a step to the job named `expo_sdk`. This should be in alphabetic order with the other testing steps. **`.circleci/config.yaml`** ```yaml - yarn: command: test --maxWorkers 1 working_directory: ~/expo/packages/expo-sms ``` ## Move native `dependencies` to `peerDependencies` In order to prevent overlapping native code in `node_modules`, we should move any `dependencies` containing native code to `peerDependencies`. ## Add module scripts **`package.json`** ```js "scripts": { "build": "expo-module build", "clean": "expo-module clean", "test": "expo-module test", "prepare": "expo-module prepare", "prepublishOnly": "expo-module prepublishOnly", "expo-module": "expo-module" } ``` ## Generate a `tsconfig.json` file with `expo-module-scripts` To get the `tsconfig` that we use in all of our modules, run `expo-module prepare` or the yarn script `yarn prepare` (given the script is defined in a module's `package.json`) **`/tsconfig.json`** ```json // @generated by expo-module-scripts { "extends": "expo-module-scripts/tsconfig.base", "compilerOptions": { "outDir": "./build" }, "include": ["./src"], "exclude": ["**/__mocks__/*", "**/__tests__/*"] } ``` ## Various Other Changes - Remove `babel-preset-expo` - Remove `flow` - For reusing types across the web implementation's native layer and API layer, types should be moved to a named file with the `.types.ts` extension. There are cases (`expo-av` for example) where you should separate types into smaller files. [universal-modules]: https://github.com/expo/expo/blob/main/guides/Expo%20Universal%20Module%20Infrastructure.md