Skip to content

Proposal for sharing source between apps #3436

Closed

Description

@bradfordlemley

This proposal is to support a simple and generic way to share code between create-react-app apps.
It can support monorepos and arbitrary source directory layout (e.g. for cleaning up relative import paths).

Example:

monorepo
  |--cra-app1
     |--package.json: srcPaths: [“../shared”]
     |--src
       |--file1.js: import comp1 from ‘comp1’ ← ok, shared/comp1
       |--file2.js: import comp1 from ‘../../shared/comp1’  ← naughty, fails
  |--cra-app2
     |--package.json: srcPaths: [“../shared”, "./packages"]
     |--src
       |--file1.js: import comp1 from ‘comp1’ ← ok, shared/comp1
       |--file2.js: import comp3 from ‘comp3’ ← ok, packages/comp3
     |--packages
       |--comp3
  |--shared
    |--comp1
    |--comp2

Proposal:

  • srcPaths are specified in package.json.
  • Modules found in srcPaths are treated essentially the same as /src modules.
    ** transpiled using same cra config
    ** do not have their own package.json, do not specify own dependencies, .babelrc, etc.
    ** all tests in modules are included when running app tests
  • Modules in a srcPath are imported between /src or another srcPath using absolute import paths.
  • Keep us sane?...don't allow overlapping srcPaths

The implementation to support this has a smallish footprint:

More info on this proposal including a working monorepo is here:
https://github.com/bradfordlemley/cra-share

I think the best part of this proposal is that it puts a lot of flexibility and power within the grasp of a novice developer. I think it works approximately how a novice developer would expect shared source to work. ...but...what are the issues with this proposal that I'm not seeing?

Activity

  1. rmhartog commented on Nov 10, 2017

    @rmhartog

    What do you see as the major differences between your proposal and something like Yarn Workspaces (https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/)? I think it will become a more 'conventional' approach to javascript monorepo's and offers enough flexibility for novice developers to be productive with.

  2. bradfordlemley commented on Nov 10, 2017

    @bradfordlemley
    ContributorAuthor

    @rmhartog
    Longer-term, the js community will surely come up with a generic way to manage source package dependencies, but it doesn’t seem to have arrived yet.

    Yarn workspaces is a step in that direction, but I think if you try to do this with yarn workspaces, you’ll find it’s not (yet) ideal for this use case. In my opinion, the root of the problem is that npm packages don’t carry the necessary metainfo to be used as source packages...they are intended as buildable libraries. Package.json could carry that extra metainfo, and I think it probably will in the future. But, that’s just my theory on yarn workspaces, I haven’t put time into proving it out, maybe you or someone else can add more info or disprove my theory.

    On the other hand, I think this srcPaths proposal provides an instant developer-friendly experience for create-react-app users -- basically, everything works the same as your standard /src, just from a different spot. The major drawback is probably that it doesn’t support dependencies of included srcPaths -- it totally punts to the top-level includer to have all of the dependencies of the srcPaths that in includes. I convinced myself to be ok with this because: (1) that’s the same as any other sources under /src, (2) if the included thing has a lot of dependencies, maybe it does belong in its own package, and (3) dependency management is hard. Dependency management would be (is?) a major win for using yarn workspaces.

  3. raycohen commented on Nov 19, 2017

    @raycohen

    Would there be a way to have versioned dependencies managed through package.json with this approach? Say for example you have two CRA projects in separate repos, and a one-way dependency, could you publish one to npm, add it to package.json from the other and consume it from a srcPath inside node_modules?

  4. bradfordlemley commented on Nov 19, 2017

    @bradfordlemley
    ContributorAuthor

    @raycohen I don't think that will work because the build won't be able to pick up cra2's dependencies (from cra1/node_modules/cra2/node_modules). (If cra1 contained cra2's dependencies, I think it would work, but I don't think that's what you were asking.)

  5. tlvince commented on Nov 20, 2017

    @tlvince

    @bradfordlemley, thanks for kicking this off. I've successfully given it a try, but have a few questions:

    Given the following project structure (a Lerna monorepo):

    packages
    ├── parent-app
    ├── component-1
    └── component-2
    

    All packages are bootstrapped with Create React App and parent-app's package.json contains:

    "srcPaths": [
      "../component-1/src",
      "../component-2/src"
    ]
    1. If both component-1 and component-2 contain e.g. a User component, can they both be imported in parent-app? I would assume one would take precedence over the other and so we'd need a way to namespace imports, maybe:
    "srcPaths": {
      "component1": "../component-1/src",
      "component2": "../component-2/src"
    }
    1. When using separate repos (not a monorepo), can we include node_modules without transpiling? It appears something like the following is unsupported (due to Enable babel-preset-env for node_modules that target newer Node versions #1125):
    "srcPaths": {
      "node_modules/component-1/src"
    }
  6. bradfordlemley commented on Nov 20, 2017

    @bradfordlemley
    ContributorAuthor

    @tlvince

    1. You could achieve that w/ srcPaths=[".."], then import User1 from 'component-1/src/User'. Or you could add another dir under component-x/src, e.g. component-1/src/comp1/User, then import User1 from 'comp1/User'. The namespace/aliasing suggestion could make the import a bit prettier without adding the extra dir (import User1 from 'component1/User'), but I think it would complicate the dev experience, e.g. to debug that import, you'd normally look for a component1 directory somewhere, but it wouldn't exist.
    2. This should work, but I haven't tried it. (Files from "node_modules/component-1/src" would be transpiled -- I think that's what you were asking.) The catch is that component-1's dependencies would not be available, so, e.g. if component-1 needs moment.js, moment would have to be included in the top-level app's dependencies. (some other comments in this thread also discuss this dependencies issue.)
  7. Timer commented on Dec 8, 2017

    @Timer
    Contributor

    Closing as dupe of #1492. Please add new proposals there.

  8. locked and limited conversation to collaborators on Jan 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions