简体   繁体   中英

Babel-node can't process flowtype files imported in Typescript file?

I got, it seems, an odd situation where I can't find an answer on the Interwebs. In those case, I think I'm doing something incorrectly or not in a standard way.

Context

Problem

My Problem is running TypeORM CLI to generate or even run migration locally for manual testing.

Failed tries

Using ts-node

Per TypeORM docs regarding entity files in Typescript , I have to run ts-node somehow in order to make it work. My problem seems to be that in my entities, I have some import of modules written in Flow , like react-native-fs or react-native-device-info .

$ yarn run typeorm migration:run
yarn run v1.22.17
warning ../package.json: No license field
$ node --require ts-node/register ./node_modules/typeorm/cli.js migration:run
Error during migration run:
/path/to/app/node_modules/react-native-fs/FS.common.js:30
var normalizeFilePath = (path: string) => (path.startsWith('file://') ? path.slice(7) : path);
                             ^

SyntaxError: Unexpected token ':'
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1025:15)
    at Module._compile (node:internal/modules/cjs/loader:1059:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:999:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/path/to/app/src/entities/Lists/ListAttachment.ts:2:1)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

OK, so. My Entity written in Typescript ( ListAttachment.ts ) has an import * as RNFS from 'react-native-fs'; . This lib is written in Flow . As I understand, ts-node will simply transpile Typescript to Javascript, so when it encounters a .js file, it can't interpret the // @flow annotation and tries to interpret it as plain JS. Thus the failure.

Using babel-node

Ok, so. My thought would be to use Babel to handle both languages, but the problem is the same. As I understand, Babel will use the transpiler based on the file extension. So if my main file is Typescript, it will not switch to another transpiler (the Flow one) if an import is in Flow.

$ ./node_modules/.bin/babel-node --extensions ".flow,.js,.ts" ./node_modules/typeorm/cli.js migration:run
Error during migration run:
/path/to/app/node_modules/react-native-fs/FS.common.js:30
var normalizeFilePath = (path: string) => (path.startsWith('file://') ? path.slice(7) : path);
                             ^

SyntaxError: Unexpected token ':'
    at compileFunction (<anonymous>)
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1025:15)
    at Module._compile (node:internal/modules/cjs/loader:1059:27)
    at Module._compile (/path/to/app/node_modules/pirates/lib/index.js:99:24)
    at Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
    at Object.newLoader [as .js] (/path/to/app/node_modules/pirates/lib/index.js:104:7)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:999:19)

Question time!

But how can React-Native's Metro handle those mixed imports?

Should I remove any external import from my entities? (Best Practice?)

Am I doing it wrong? (certainly :D)

Thank you fellow developers 🙏

File references

babel.config.js

module.exports = {
    presets: ['module:metro-react-native-babel-preset'],
    plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
};

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "*": ["types/*"] },
    /* Basic Options */
    "target": "esnext",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "jsx": "react-native",                    /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "noEmit": true,                           /* Do not emit outputs. */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */
    "strictNullChecks": true,                 /* Enable strict null checks. */

    /* Module Resolution Options */
    "moduleResolution": "node",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "allowSyntheticDefaultImports": true,     /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */

    /* Experimental Options */
    "experimentalDecorators": true,           /* Enables experimental support for ES7 decorators. */
    "emitDecoratorMetadata": true,            /* Enables experimental support for emitting type metadata for decorators. */

    "skipLibCheck": true
  },
  "exclude": [
    "node_modules",
  ],
}

.flowconfig

[ignore]
; We fork some components by platform
.*/*[.]android.js

; Ignore templates for 'react-native init'
<PROJECT_ROOT>/template/.*

; Ignore the Dangerfile
<PROJECT_ROOT>/bots/dangerfile.js

; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/

; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
.*/node_modules/warning/.*

; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js

[untyped]
.*/node_modules/@react-native-community/cli/.*/.*

[include]

[declarations]
.*/node_modules/.*

[libs]
interface.js
flow/

[options]
emoji=true

esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable

exact_by_default=true

module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js

munge_underscores=true

module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/index.js'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/Libraries/Image/RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_type=$FlowFixMeEmpty

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

experimental.well_formed_exports=true
experimental.types_first=true
experimental.abstract_locations=true

[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error

[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import

[version]
^0.113.0

Using babel-node should work (as AFAIK the TypeScript compiler - that ts-node uses - cannot strip Flow types), but you'd need a Babel config that both uses @babel/preset-flow on .js files & @babel/typescript on .ts files, eg (not tested):

module.exports = {
  presets: ['module:metro-react-native-babel-preset', '@babel/preset-flow'],
  overrides: {
    test: /\.tsx?$/,
    presets: [
      '@babel/preset-env',
      '@babel/preset-react',
      [
        '@babel/typescript',
        {
          allExtensions: true,
          isTSX: true,
        },
      ],
    ],
    plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
  },
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM