简体   繁体   English

使用 npm package 导出我自己的流类型?

[英]Exporting my own Flow type with npm package?

I have a npm package of React components which are using flow for type-checking.我有一个使用流进行类型检查的 React 组件的 npm package。

It would be useful for the users of my components to have access to my flow types.对于我的组件的用户来说,访问我的流类型会很有用。 However at the moment I am compiling my code using Babel which strips all type information.然而,目前我正在使用 Babel 编译我的代码,它会去除所有类型信息。

My project structure is as follows:我的项目结构如下:

|
|- flowdecls
       myTypes.js
| -components
    - Component1
        Component1.js
| - lib
    - Component1.js (compiled using Babel)
    - Component1.js.flow (created using flow-copy-source)


For example one of my types in myTypes.js is例如,我在myTypes.js中的一种类型是

declare type DataItemIconType = {
    iconElement: React$Element<React$ElementType>,
    color?: string,
    hoverColor?: string
}

which I would using in Component1 .我将在Component1中使用。 For example one of the props of Component1 would be例如Component1的道具之一是

iconList : Array<DataItemIconType>

I have already published several versions of my library of React components as an npm package without Flow and my components are being widely used.我已经发布了我的 React 组件库的几个版本作为 npm package 没有 Flow 并且我的组件正在被广泛使用。 However I would really like to provide flow support.但是我真的很想提供流量支持。

In my most recent I tried using flow-copy-source as specified in this article ( Authoring and publishing JavaScript modules with Flow ) but users of my library still can't access my types.在我最近尝试使用本文中指定的flow-copy-source使用 Flow 创作和发布 JavaScript 模块)但我的库的用户仍然无法访问我的类型。

How would I make a type such as DataItemIconType available to someone using Component1 in my library?我如何让在我的库中使用Component1的人可以使用DataItemIconType之类的类型?

package.json package.json

{
  "name": "@company/react-common-components-build-template",
  "version": "0.6.0",
  "main": "./lib/index.js",
  "private": true,
  "engines": {
    "node": ">=4.0.0"
  },

  "files": [
    "lib"
  ],
  "description": "Common component library",
  "peerDependencies": {
    "react": "16.10.0",
    "react-dom": "16.10.0",
    "prop-types": "15.7.2"
  },
  "dependencies": {
    "@material-ui/core": "4.9.5",
    "@material-ui/icons": "4.9.1",
    "@material-ui/lab": "3.0.0-alpha.30",
    "@material-ui/styles": "4.9.0",
    "lodash": "4.17.15"
  },
  "devDependencies": {
    "@babel/cli": "7.4.4",
    "@babel/core": "7.6.0",
    "@babel/node": "7.2.2",
    "@babel/plugin-proposal-class-properties": "7.2.1",
    "@babel/plugin-syntax-dynamic-import": "7.2.0",
    "@babel/plugin-transform-object-assign": "7.2.0",
    "@babel/plugin-transform-react-constant-elements": "7.6.0",
    "@babel/plugin-transform-runtime": "7.6.2",
    "@babel/preset-env": "7.4.2",
    "@babel/preset-flow": "7.0.0",
    "@babel/preset-react": "7.0.0",
    "@babel/register": "7.0.0",
    "@svgr/webpack": "4.3.2",
    "@typescript-eslint/eslint-plugin": "^2.2.0",
    "@typescript-eslint/parser": "^2.2.0",
    "babel-eslint": "10.0.3",
    "babel-jest": "24.9.0",
    "babel-loader": "8.0.6",
    "babel-plugin-named-asset-import": "0.3.4",
    "babel-plugin-react-remove-properties": "0.3.0",
    "babel-preset-react-app": "9.0.2",
    "camelcase": "^5.2.0",
    "case-sensitive-paths-webpack-plugin": "2.2.0",
    "chokidar": "1.6.1",
    "classnames": "2.2.6",
    "cpx": "1.5.0",
    "cross-env": "6.0.3",
    "css-loader": "2.1.1",
    "dotenv": "6.2.0",
    "dotenv-expand": "5.1.0",
    "enzyme": "3.10.0",
    "enzyme-adapter-react-16": "1.15.1",
    "enzyme-to-json": "3.4.3",
    "eslint": "6.6.0",
    "eslint-config-react-app": "5.0.2",
    "eslint-loader": "3.0.0",
    "eslint-plugin-flowtype": "3.13.0",
    "eslint-plugin-flowtype-errors": "4.1.0",
    "eslint-plugin-import": "2.18.2",
    "eslint-plugin-jsx-a11y": "6.2.3",
    "eslint-plugin-react": "7.16.0",
    "eslint-plugin-react-hooks": "^2.3.0",
    "file-loader": "3.0.1",
    "flow-bin": "0.113.0",
    "flow-copy-source": "^2.0.9",
    "flow-typed": "^2.6.2",
    "fs-extra": "7.0.1",
    "glob-gitignore": "1.0.14",
    "hard-source-webpack-plugin": "^0.13.1",
    "highlight": "^0.2.4",
    "highlight.js": "^9.10.0",
    "html-webpack-plugin": "4.0.0-beta.5",
    "husky": "3.0.8",
    "identity-obj-proxy": "3.0.0",
    "is-wsl": "^1.1.0",
    "jest": "24.9.0",
    "jest-environment-jsdom-fourteen": "1.0.1",
    "jest-enzyme": "^7.1.2",
    "jest-resolve": "24.9.0",
    "jest-watch-typeahead": "0.4.0",
    "mini-css-extract-plugin": "0.9.0",
    "npm-run-all": "4.0.2",
    "optimize-css-assets-webpack-plugin": "5.0.3",
    "pnp-webpack-plugin": "1.5.0",
    "postcss-flexbugs-fixes": "4.1.0",
    "postcss-loader": "3.0.0",
    "postcss-normalize": "7.0.1",
    "postcss-preset-env": "6.7.0",
    "postcss-safe-parser": "4.0.1",
    "prettier": "1.19.1",
    "react": "16.10.0",
    "react-addons-test-utils": "15.5.1",
    "react-app-polyfill": "^1.0.3",
    "react-dev-utils": "10.2.0",
    "react-docgen": "3.0.0",
    "react-dom": "16.10.0",
    "react-highlight": "^0.12.0",
    "react-test-renderer": "16.10.0",
    "resolve": "1.15.0",
    "resolve-url-loader": "3.1.1",
    "sass-loader": "8.0.2",
    "semver": "6.3.0",
    "style-loader": "1.0.0",
    "terser-webpack-plugin": "2.3.4",
    "ts-pnp": "1.1.5",
    "url-loader": "2.3.0",
    "webpack": "4.41.5",
    "webpack-dev-server": "3.10.2",
    "webpack-manifest-plugin": "2.2.0",
    "workbox-webpack-plugin": "4.3.1"
  },
  "scripts": {
    "prestart": "npm run gen:docs",
    "start": "npm-run-all --parallel start:docs gen:docs-watch",
    "start:docs": "node scripts/start.js",
    "gen:docs": "node scripts/generateComponentData.js",
    "gen:docs-watch": "npm run gen:docs -- --watch",
    "build:docs": "node scripts/build.js",
    "test": "node scripts/test.js",
    "predeploy:docs": "npm run build:docs",
    "flow": "flow",
    "lint": "eslint src --debug",
    "lint:flow-typed": "flow-typed install --ignoreDeps dev",
    "build:images": "cpx \"./src/components/images/**/*.*\" ./lib/images",
    "prebuild:common-components-lib": "rimraf lib",
    "build:common-components-lib": "npm-run-all --parallel build:components build:utils build:images build:copy-files build:copyflowsource",
    "build:components": "cross-env NODE_ENV=production BABEL_ENV=cjs babel ./src/components --out-dir ./lib/ --ignore spec.js",
    "build:utils": "cross-env NODE_ENV=production BABEL_ENV=cjs babel src/components/utils --out-dir ./lib/utils --ignore spec.js",
    "build:copyflowsource": "flow-copy-source ./src/components ./lib ",
    "build:copy-files": "node scripts/copyBuildFiles.js",
    "prettier:changed": "node ./scripts/prettier.js",
    "prettier:all": "node ./scripts/prettier.js write",
    "format-check": "prettier --check \"./src/**/*.{js,test.js,spec.js}\""
  },
  "publishConfig": {
    "registry": "http://srv-ie-nexus/repository/npm-hosted/"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "jest": {
    "roots": [
      "<rootDir>/src/components"
    ],
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,ts,tsx}",
      "!src/**/*.d.ts"
    ],
    "setupFiles": [
      "react-app-polyfill/jsdom"
    ],
    "setupFilesAfterEnv": [
      "<rootDir>/jest-test-setup.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
      "<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
    ],
    "testEnvironment": "jest-environment-jsdom-fourteen",
    "transform": {
      "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
      "^.+\\.module\\.(css|sass|scss)$"
    ],
    "modulePaths": [],
    "moduleNameMapper": {
      "^react-native$": "react-native-web",
      "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
    },
    "moduleFileExtensions": [
      "web.js",
      "js",
      "web.ts",
      "ts",
      "web.tsx",
      "tsx",
      "json",
      "web.jsx",
      "jsx",
      "node"
    ],
    "watchPlugins": [
      "jest-watch-typeahead/filename",
      "jest-watch-typeahead/testname"
    ]
  }
}

I don't think flow has a solution to this yet.我认为 Flow 还没有解决这个问题的方法。 But I was in the same boat as you.但我和你在同一条船上。

Pretty much the reason your consumers aren't able to use your package types are because they read global types from their .*/flow-typed/* not your one which when they install your package will be in .*/node_modules/@company/react-common-components-build-template .您的消费者无法使用您的 package 类型的原因几乎是因为他们从.*/flow-typed/*中读取全局类型,而不是您的,当他们安装 package 时将在.*/node_modules/@company/react-common-components-build-template It has nothing to do with any package.json settings.它与任何 package.json 设置无关。

You have two options though to ship your package with types.不过,您有两种选择来运送您的 package 类型。

Option 1:选项1:

Either you put them as part of your src code and allow them to import it, which means your types won't be global anymore and you need to import the types you want to use within your source code.要么将它们作为src代码的一部分并允许它们导入它,这意味着您的类型将不再是全局的,您需要导入要在源代码中使用的类型。 But this means so can you consumers.但这意味着你的消费者也可以。

Option 2:选项 2:

Or keep them in your flowdecls and ensure they're published.或者将它们保存在您的flowdecls中并确保它们已发布。 Once they are, your users will have to copy your type defs into their flow-typed dir, which will now make them global within their project also.一旦它们是,您的用户将不得不将您的类型定义复制到他们的flow-typed目录中,这现在将使它们在他们的项目中也是全局的。

You can add something like the following into your README to give users some insight:您可以在 README 中添加如下内容,以便为用户提供一些见解:


react-common-components-build-template also uses global type definitions internally. react-common-components-build-template也在内部使用全局类型定义。 If you would like to take advantage of this, you can copy /node_modules/@company/react-common-components-build-template/flowdecls/myTypes.js to your local flow-typed directory.如果您想利用这一点,可以将/node_modules/@company/react-common-components-build-template/flowdecls/myTypes.js复制到本地流类型目录。 It's probably a good idea to do a copy once per version upgrade so you stay in-sync with the latest changes which you can do via npm scripts.每次版本升级都复制一次可能是个好主意,这样您就可以与通过 npm 脚本进行的最新更改保持同步。

"scripts": {
  // ...
  "postinstall": "cp /node_modules/@company/react-common-components-build-template/flowdecls/myTypes.js flow-typed"
},

The second option is actually what I've gone with, and the above is what I have in my repo.第二个选项实际上是我已经使用的,上面是我在我的回购中拥有的。 As a side note, I would recommend though that you rename your dir to flow-typed and your types file to something like react-common-components-build-template.js so that when the copy process happens, people don't wonder what myTypes.js is used for.作为旁注,我建议您将 dir 重命名为flow-typed并将您的 types 文件重命名为react-common-components-build-template.js之类的东西,这样当复制过程发生时,人们不会想知道什么myTypes.js用于。

Flow will automatically look for adjecent module.js.flow declarations files , if present. Flow 将自动查找相邻的module.js.flow声明文件(如果存在)。

For example, if you have a main field that points to dist/index.js , then adding dist/index.js.flow to your package's outputs will have it picked up by the user's language server.例如,如果您有一个指向dist/index.js的 main 字段,那么将dist/index.js.flow添加到您的包的输出中,它将被用户的语言服务器拾取。

This looks to be a very useful package as part of this process also - https://www.npmjs.com/package/gen-flow-files这看起来是一个非常有用的 package 作为此过程的一部分 - https://www.npmjs.com/package/gen-flow-files

For that you can use:为此,您可以使用:

  • flow-remove-types NPM package which will create lib/Component1.js without flow types. flow-remove-types NPM package 将创建没有流类型的lib/Component1.js Or do it with Babel if you want或者,如果您愿意,可以使用 Babel
  • flow-copy-source NPM package which will copy flow typed files to the destination folder with the.flow suffix lib/Component1.js.flow flow-copy-source NPM package 这会将流类型文件复制到目标文件夹,其后缀为.flow lib/Component1.js.flow

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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