Skip to content
This repository has been archived by the owner on Jan 26, 2019. It is now read-only.

Sharing code between multiple projects #260

Open
JNaftali opened this issue Feb 22, 2018 · 17 comments
Open

Sharing code between multiple projects #260

JNaftali opened this issue Feb 22, 2018 · 17 comments

Comments

@JNaftali
Copy link

Hello. I'm trying to prototype sharing TS code between a web and a react-native application. At the moment my directory structure looks like this:

/              <-- project root
  web          <-- folder created by create-react-app-typescript
    src
      shared   <-- symlink to ../../shared
      App.tsx
  native       <-- folder created by create-react-native-app
  shared       <-- folder with .ts and .tsx files I'd like to share between both directories
    x.js
    x.tsx

Working inside of App.tsx, if I try to import { foo } from './shared/x.js' I can do so without any trouble. However if I try to import { foo } from './shared/x.tsx' I get errors that make it sound like x.tsx is not getting compiled.

Any advice on how to solve this issue? Ideally by teaching ts to properly resolve symlinks.

@DorianGrey
Copy link
Collaborator

DorianGrey commented Feb 22, 2018

[...] I get errors that make it sound like [...]

Can you be a bit more precise on this, i.e. provide the error output?

@JNaftali
Copy link
Author

JNaftali commented Feb 22, 2018

I don't actually have them on hand, unfortunately - I've kept iterating as the day went on. When importing a named export (import {foo} from '../shared/file) foo was undefined, and when importing a default export (import foo from '../shared/file) the shared file was erroring with an illegal character. Same file otherwise, only difference was export vs export default

@JNaftali
Copy link
Author

if that isn't enough info, feel free to close the issue. I'd understand

@DorianGrey
Copy link
Collaborator

I'd be happy to help, but without any reproduction project or at least the error message(s), it's hard to figure something out.

@JNaftali
Copy link
Author

Lemme see if I can reproduce it - I have more time today than yesterday

@JNaftali
Copy link
Author

@DorianGrey
Copy link
Collaborator

Hm... are you sure this repo illustrates the error you're receiving? I don't get any, though.

  • Cloned the repo
  • Switched to the web folder
  • yarn
  • yarn start

=> No errors in terminal, and app works fine.

@JNaftali
Copy link
Author

JNaftali commented Mar 2, 2018

the 'shared' folder contains two files (jstest.js and tstest.ts) each with identical code. Each file exports two strings, one as a named export and one as a default export. I try to reference all 4 of the strings in App.tsx but only the strings exported from jstest.js make it through. The named TS export is replaced by what appears to be a partial file path, and the default export is replaced by undefined

@DorianGrey
Copy link
Collaborator

Hm, I see.

This is what I get when logging these entries (same order as in your code):

App.tsx:8 This is a js named export
App.tsx:9 This is a js default export
App.tsx:10 undefined
App.tsx:11 /static/media/tstest.e6792449.ts

The last entry is a file path generated by file-loader, which serves as a fallback for all files that have not been processed otherwise (the "oneOf" rule).
Most of the rules in there have a limited inclusion scope, paths.appSrc in most cases. While this path is forcefully resolved via the paths configuration, this does not seem to affect any paths inside of it.
There is a known (huge, unlikely) glitch regarding symlink resolution in webpack (quite old, but still active: webpack/webpack#1643).
Setting symlinks: false in the resolve part of your webpack config should solve this - at least the result in my case was:

App.tsx:8 This is a js named export
App.tsx:9 This is a js default export
App.tsx:10 this is a ts named export
App.tsx:11 this is a ts default export

But beware of the potential side-effects this might have - see https://webpack.js.org/configuration/resolve/#resolve-symlinks.
Suppose that's why this option is true by default. Thus, you won't be able to change it without ejecting or using unofficial overwriting utilities.

@JNaftali
Copy link
Author

JNaftali commented Mar 2, 2018

I suppose I could also fork your version of react-scripts... but whatever I end up doing, thank you so much for your help with this and all the work you've done on this project!

@StanleyGoldman
Copy link

@JNaftali I just ran into this problem and was about to create an issue for it.
How did you resolve the issue?

@untsamphan
Copy link

It seems like webpack doesn't like symlinks: webpack/webpack#1643
So CRA has this same problem: facebook/create-react-app#1333

They recommend we share code with yarn/lerna workspace. CRA support for workspace already landed on 2.0: facebook/create-react-app#3815

So we should get it when CRA 2.0 is merged?, IIUC.

@JNaftali
Copy link
Author

JNaftali commented Jun 4, 2018

My work hasn't started on the project for which we require this, so we haven't settled on an answer yet. We're not too enthused about workspaces so we're considering using git submodules.

Another alternative is making sure TS transpiles dependencies and declaring that folder as a dependency (stackoverflow link)

@untsamphan
Copy link

I've implemented a workaround using tsc's baseUrl which CRA-ts already supported.

https://github.com/untsamphan/cra-ts-monorepo-example

Need to eject (only) if you want tsc/webpack to grab .ts from the local packages.

Steps

  1. Initial boilerplate from create-react-app-typescript in root/webapp commit.

  2. Create yarn workspace commit.

  3. Move CRA tsconfig.json to root to be shared with other local packages commit 1, commit 2.

  4. Implement a trivial local packages root/packages/mymain commit. Run yarn now so it'll create symlink to mymain in root/node_modules. Then we can import from 'mymain' from anywhere.

  5. Make the CRA app use the new local packages commit. Now the CRA app will tsc compile correctly (because we have index.ts at mymain root). But when yarn start it'll fail in browser because mymain isn't built. To fix this we can tsc in mymain to build the package and the app will run successfully. However, when we go to definition to a symbol in mymain, it'll goto a .d.ts.

  6. To achieve goal 3 (go to definition -> .ts), we configure tsconfig.json baseUrl to directly reference local packages. Since webpack won't bundle code outside webapp/src, and jest won't find the packages, we have to eject to configure them. commit

  7. Simple webpack config hack to allow it to bundle code outside webpack/src. This to achieve goal 3. commit. Don't forget to delete build in local packages, because otherwise everyone will use build/index.* (per NPM spec) instead of index.ts at the local package root (a TS-specific behavior).

  8. Simple jest config hack to make jest inside webapp also run all tests in local packages. commit

@fwouts
Copy link

fwouts commented Sep 12, 2018

Now that TypeScript 3.0 introduced project references, it looks like we just need to wait for ts-loader to support project references and we'll then be able to use that?

See TypeStrong/ts-loader#815 for reference.

@FredrikNoren
Copy link

Looks like ts-loader has support for this now (815 is closed)

@JNaftali
Copy link
Author

when one issue closes, another one opens - TypeStrong/ts-loader#851

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants