TL;DR: A new module.system.node.main_field option for trying to resolve different package.json fields (other than package.json#main)
[options]
module.system.node.main_field='source'
module.system.node.main_field='main'
package.json#main or package.json#moduleIt is not uncommon to see package.json files that look like this:
{
"name": "my-package",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js"
}
Tools like Webpack, Rollup, and others will look at fields like package.json#module in addition to package.json#main when resolving dependencies.
The specific reason that I want Flow to have something similar is to support Workspaces.
Right now in order to support workspaces you need to have some very brittle module.name_mapper configuration:
# .flowconfig
[options]
module.name_mapper='^@scope\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_ROOT>/packages/[^/]+/\1/src/index'
Effectively:
@scope/*→/packages/*/src/index.js
This can break in a number of different ways, but I won't dive into all those.
module.system.node.main_fieldIf we could configure Flow like:
[options]
module.system.node.main_field='source'
module.system.node.main_field='main'
We could write our workspace package.json files like this:
{
"name": "my-package",
"main": "dist/index.js",
"source": "src/index.js"
}
And Flow could check for package.json#source before package.json#main.
The basic resolve process in Flow would look like this:
For each main_field:
package.json has a field with that namepackage.json does not have the field, continue to next main_fieldmain_fieldThe relevant bits of code seem to be:
https://github.com/facebook/flow/blob/9c75e15cc8809170933236c2add89a4646b04f44/src/parser_utils/package_json.ml#L40-L63
https://github.com/facebook/flow/blob/2ff56f4e7620b2d3d28cb862047449d3cbfd615b/src/services/inference/module_js.ml#L328-L371
This doesn't seem too difficult. I'll try to find time to take a swing at this this week.
Ended up using this to procrastinate going to the gym ๐
@thejameskyle thanks for spec'ing this out so thoroughly!
My current implementation differs from your request slightly. You wrote
- If it field exists, check for a file at that location.
- If no file at that location exists, continue to the next main_field
Whereas my PR just chooses the first main_field field it finds in the package.json.
I built it that way since it was easier to code, it's a slightly more simple behavior, and because I didn't read your spec carefully enough. How important is the file-exists behavior to you? It's a little tricky to build, since files appearing and disappearing can change which "main_field" is selected. It's also a more complicated behavior, which can be trickier for users to understand.
@gabelevi @thejameskyle We need to decide which name we usually want to use. Something like "flow_source" or similar. Otherwise many projects which also use such naming can be treated as untyped.
@gabelevi the behavior is important when it comes to consuming published packages that have an main field pointing to the uncompiled source but the source was omitted from npm.
{
"main": "dist/index.js",
"source": "src/index.js",
"files": ["dist"]
}
I've tried a few methods for doing something like this and I've settled on a pretty simple solution, although it does requiring publishing src/. It works like this:
my-pkg/
โโ dist/
โ โโ index.js
โ โโ index.js.flow
โ โโ index.mjs
โโ src/
โ โโ index.js
โโ package.json
package.json
{
"name": "my-pkg",
"main": "dist/index.js",
"module": "dist/index.mjs",
"files": ["dist", "src"]
}
dist/index.js.flow
// @flow
export * from "../src/index.js";
All that's required is the extra index.js.flow stub file in dist/. This works perfectly inside yarn workspaces and for folks consuming the package via npm.
@rtsao Yeah, but it still requires you to have a build step to make sure everything is up to date before Flow will work
+1 for this feature.
First time flow user, this is one of the first things I looked for.
Most helpful comment
Ended up using this to procrastinate going to the gym ๐