facebook/create-react-app

Document maintaining a fork of react-scripts as an alternative to ejecting

gaearon opened this issue ยท 85 comments

It is not common knowledge that you can fork react-scripts, publish your fork, and then do create-react-app my-app --scripts-version my-react-scripts-fork.

This can be useful for customized setups, especially if you want to merge upstream updates once in a while. And with something like https://github.com/1egoman/backstroke, it might not even be painful!

We should document this. Help welcome!

I tried this before. (0.2 maybe). But the global cli doesn't install the custom script. Was it fix?

We are going to be forking react-scripts and attempting to move our build process over to it @trunkclub. I'll talk to the team but I think we could write documentation as we go through the process.

But the global cli doesn't install the custom script. Was it fix?

There was a bug but should be fine with 0.4.3.

This is supper awesome (...if I understood correctly), Thank you! I'm loving create-react-app, but in the current state it felt like you either embrace it as it is (minimal), or move away. And "Eject" makes you feel like you're being ungrateful with the maintainers.

Now with this approach, and in my company, I can be the one maintaining the custom scripts while still keeping my teammates away from the struggle of battling configuration files.

For instance, I'd just add less-css support, and still benefit from the core create-react-app features and updates.

I just run a short custom script after create-react-app does its thing so that I can support CSSModules. All it does is alter two lines in the webpack config scripts (css loader delacarations).

Seemed like overkill to fork and publish, but maybe that's the way to go?

@kirkaustin you don't need to publish it. You can install it directly from github

@thangngoc89 Not sure I understand. At my company we have an enterprise GitHub account. Are you suggesting that I can have my fork pulled from there?

You're using npm to install dependencies right? You can do this npm install git+ssh://git@github.com/your-company/react-scripts-fork . You don't need to publish the scripts to npm and then install it.

Great, thanks!

Just curious if anyone has gotten a forked version of react-scripts via direct-from-github npm install working with the most recent create-react-app repository code? @thangngoc89

With the switch by create-react-app to using lerna and as a result react-scripts moving into the packages/react-scripts subdirectory, it doesn't seem possible to install a forked react-scripts directly from github any longer (since npm cannot install from a github repo subdirectory), or am I missing something?

Previously forking the entire repo (and referencing via github url) worked because react-scripts was the package specified in the repo's root package.json, but that's no longer the case it seems.

So is publishing a custom npm package then the only way to take advantage of this approach?

So for now I went down the path of using a custom published npm package (like react-scripts-custom-whatever), but it still seems like there's at least one issue that prevents this from working which is that the react-scripts package name is hardcoded in at least one spot, which won't work if you're using a custom forked package: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/scripts/init.js#L17

The end result for me is that create-react-app fails at executing the init script. Has anyone been successful with this approach with the most recent version of react-scripts (0.4.3), and I'm just doing something wrong?

Edit: after looking at how e2e.sh runs its --scripts-version react-scripts-fork test successfully, it looks like the solution used in that fork was to just change the hardcoded package name in the line I referenced above in the fork to be the forked package name.

Last edit: Here are all the steps I used to get a custom fork working in case anyone else gets as stuck as I did ๐Ÿ˜ƒ

  1. Forked the create-react-app repo and cloned it locally
  2. Changed the package name in packages/react-scripts/package.json to be a new custom name
  3. Changed the 'react-scripts' reference in packages/react-scripts/scripts/init.js#L17 to match the new package name I chose
  4. Then I did a cd packages/react-scripts followed by an npm publish which published successfully
  5. Which then resulted in create-react-app test-app --scripts-version react-scripts-my-custom-package working as expected

it still seems like there's at least one issue that prevents this from working which is that the react-scripts package name is hardcoded in at least one spot, which won't work if you're using a custom forked package: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/scripts/init.js#L17

PR to fix this would be welcome. ๐Ÿ˜‰

I'm actually in favour of (maybe) just telling people to fork the entire monorepo and publish create-whatever-app and whatever-scripts. It would be good if you didn't have to change react-scripts and create-react-app strings in 100 places as your first change though. I would suggest putting both of these strings in some kind of names.js package in each project. That way there would be just two places it would need changing.

I wonder if we should suggest people use code to generate their fork, rather than forking by hand. e.g. they could write code like overwrite webpack.config.js with this file. That way updating the fork would just mean re-running the code to generate the fork against the latest version of create-react-app.

Alternatively, should we just encourage people to hard-fork once create-react-app is sufficiently stable?

@kirkaustin exactly what I need as well. Will give that option a try.

The end result for me is that create-react-app fails at executing the init script.

This was fixed in 0.5.1, I removed hardcoded project name.

I want to make a fork for react chrome extensions.

@gaearon You say that you can fork react-scripts. But react-scripts is not a git repo. Is the idea that I just copy the code of react-scripts in a new git repo and publish that to github?

You can fork the whole repo but publish and change that single package.

kitze commented

Anyone has an idea why this forked version doesn't work?

I'm getting the same error as @dpoineau. When I'm changing the npm script in the package.json from "start": "custom-react-scripts start", to "start": "react-scripts start" then it works.

Probably it's a silly 1 line fix that I'm missing somewhere.

EDIT: i fixed this by renaming ./bin/react-scripts to ./bin/custom-react-scripts and also changed it in package.json

"bin": {
    "custom-react-scripts": "./bin/custom-react-scripts.js"
}

๐ŸŽ‰

Tip to anybody using npm link in development to make changes to their react-scripts fork take effect immediately: comment out these lines. Otherwise, changes in your app won't be seen.

@clessg Ideally we wouldnโ€™t have to do this. Do you have an alternative solution? We could completely get rid of remove-on-publish and only leave remove-on-eject. Let me file an issue.

I just tried to summarize everything on this topic here:

Tweaking Configuration for React Scripts in Create React App.

Hope this helps!

kitze commented

Thanks @shubheksha !

I also just published an article on this topic.

Configure create-react-app without ejecting โ

thank you all, I successfully created a fork of react-scripts and everything works! After all, now, it turns out to be very easy than I thought. Are anyone working to add this to document? @zperrault

Hi guys, I follow @shubheksha instruction and rewrite it as a section in User Guide, in this PR. I hope it can help.

Because I didn't see anyone claim to work on this yet, so I want to start a PR and we can discuss more. In case @zperrault or anyone have worked on this already, I am totally ok to close my PR.

I don't see the reason to go through all the trouble of publishing a package and polluting npmjs.com with create-react-app forks, when you can just npm link your forked version.

@ivosabev in our case, I publish my forked package (companyname-react-scripts) so my team can npm install it from their machine to start working with the app. The forked version is a devDependencies in the result source code created by CRA.

I understand your particular case, but is that the general one? For the documentation it might be even better to use an example with a dependency from a git repository, instead of publishing or even npm link.

 "dependencies": {
  "react-scripts": "git+https://<TOKEN>:x-oauth-basic@github.com/<USER>/<FORK>.git"
}

ah yes, I agree. In fact we did use that solution. We use npm link to run create-react-app, then after that, we change our company-react-scripts dependency's link to our github, then everyone can work on the app source code like normal.

I just didn't think that should be wrote in the guide.. I thought that publish to npm is a more generic way. I'm not so sure about this.

The performance of npm is way better than git for package downloads. It also lets you manage versions properly and saves you from a common problem of installation not working when you try and install on a device that doens't have git in the PATH.

I think what we should encourage is scoped packages (https://docs.npmjs.com/misc/scope):

They can name the package @companyname/react-scripts then publish using:

npm publish --access public

If you want, you can even make it a private npm package if you pay a small fee to npm and omit the --access public.

@ForbesLindesay yes I think that solution will suit most people here. I think most of us just want a slightly customized version for internal use within their team/company/project.

Ooh I like the scoped package suggestion. @dvkndn Letโ€™s put it in the doc?

Ok, scoped package seems the most suitable

@gaearon @dvkndn when testing with a scoped package I found one bug that causes create-react-app to fail : #848

Edit: nevermind, @dvkndn pointed out that there's already an open PR to address this at #826

Maybe eject could setup local fork instead?

// EDIT

Indeed, I've just "ejected" my project by copying react-scripts to packages/react-scripts in my project and updating version in package.json to ./packages/react-scripts.

@gaearon Isn't it in line with monorepo approach you're encouraging? I think it could be default form of ejecting.

Working on this at @trunkclub and I am not sure how I should publish just the fork of the react-scripts package. Running npm run publish as the CONTRIBUTING documentation states wants to update versions for all of the packages. Running npm publish in packages/react-scripts doesn't do all of the fancy extra stuff...

@zperrault we are discussing some solutions for this in the PR, please take a look #779

What's the process to use a fork of react-scripts after a project has been already been created with CRA?

@timarney You should be able to uninstall react-scripts and install your fork.

npm uninstall --save react-scripts
npm install --save-dev --save-exact @your-fork-of/react-scripts

Hey @timarney , all are the same except the last step: instead of running create-react-app command to create a new app with your fork, you just need to replace react-script in your app's package.json with your fork :D

@zperrault @dvkndn perfect thanks.

Has anyone tried using https://github.com/1egoman/backstroke yet to sync a fork?

@timarney We are using backstroke @ Trunk Club to get PRs to our fork from upstream.

@zperrault thanks for letting me know. Trying to figure out what I'm doing wrong. The interface won't allow me to setup a link.

I setup:

From: facebookincubator/create-react-app
To: timarney/create-react-app

No permission to add a webhook to the repository facebookincubator/create-react-app. Make sure timarney has given Backstroke permission to access this organisation or repo via OAuth

@timarney Ah. We are using the older version.

@zperrault okay that makes sense. Are you using the way listed as Backstroke classic? Or something older.

Classic way says:

1. Create a webhook in either a fork or a upstream repository. (Settings => Webhooks & Services => Add Webhook)
2. Add http://backstroke.us as the payload url.
3. Create the webhook, and push some code to the upstream repository to see Backstroke in action.

@gaearon did you file an issue for the workaround @clessg raised around removing these lines? For my workflow at least, using npm link is much easier and faster than publishing scoped packages, even if they're marked private.

Can we change L75 from:

if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) {

to

if (process.env.npm_lifecycle_event === 'publish') {

so this gets skipped when linking to react-scripts?

If you could submit a PR detailing your fix and how to verify it works it would help!

@gaearon: here you go: #1122.

FWIW, I'm not sure if the paths even need to be set up for publishing in the first place. Won't the right paths get used at runtime for the non-ejected and ejected versions already defined above the ones used for publishing in the existing code?

EDIT: based on my latest commit, I think differentiating between the "fromApp" and "fromOwn" cases is still necessary.

I'm definitely interested in doing this. It seems like the nicest way to abstract project configuration so you don't have to maintain it in every app you build. Being able to occasionally take in updates from upstream is a huge plus too.

One thing I don't understand is how Backstroke can help, thoughโ€”I tried setting it up, but it says it needs permission from the "from" repository first. The current PR doesn't say much about this, other than that the tool could help. Is this something that needs to be set up on this repository first, before people can use this tool to pull in changes automatically?

@msikma you'll need to use what Backstroke describes as the 'classic' setup -

#682 (comment)

backstroke

The result:
https://twitter.com/timarney/status/805585512887189504

Thanks, sorry I missed that. ๐Ÿ‘ I'll add a note to the PR asking if maybe this is worth including, or linking to at least.

Is there a reason to keep react-scripts as part of a monotholic create-react-app instead of having it as it's own repo? It is already added as a dev dependency.

Having it as a seperate repo would allow people to fork it and then install/update directly from github without having to publish to NPM and easily be able to keep up to date with the upstream repo.

I agree, it would be nicer for that use case. It's just too complex a setup right now if you want to fork react-scripts. But this repo is structured as a monorepo deliberately, and that has its advantages too.

@timarney Did you need to do anything special to get backstroke working?
I have tried both normal and classic modes, and neither work...
Any chance you could show a screenshot of the web hook setup page?

@thtliife I haven't actively maintained my fork as I've opted to use another method (https://github.com/timarney/react-app-rewired)

That said I just looked at my fork of this repo and there hasn't been any recent 'auto' pull requests from backstroke. In fact I only received 1 in the lifetime of my fork (Dec 4th 2016). Quite possible this is no longer working.

It would be interesting to learn why.

@gaearon I'll dig into it further if I can find some "downtime" this week to mess around with it.

Timer commented

backstroke just fixed support for forks last night after discussion here: #1545

Awesome. I love when discussions here lead to fixes elsewhere. ๐Ÿ˜„

I am using backstroke for https://github.com/thtliife/create-react-app/tree/react-scripts-pluggable (A simple webpack plugin injector) and this mornings upstream merges worked beautifully.

The only part I'm unhappy about is that I can't maintain more than one fork of the create-react-app, so my work on various scripts versions can only really live in branches, and never get merged back into the master branch... :(

g3r4n commented

I'm trying to create a fork of react-scripts and got the following error when using it with CRA :
Error: Cannot find module 'react-dev-utils/crashOverlay'
This is because the react-dev-utils/crashOverlay.js file hasn't been publish on npm yet.
Publishing to npm from master seem to be a bad idea.

Timer commented

Hi @g3r4n.
You should be forking 0.9.x for the time being, not master!

g3r4n commented

@Timer it's possible to fork a branch ? I think you fork the entirely repository not only a branch.
We should put in the documentation an explanation about creating a branch from a tag to avoid this issue.
As soon as I'll finish my customisation of react-scripts i will create a PR.

Timer commented

We realized this caused a lot of pain for people tracking our fork (and will do this differently in the future), but effectively, you just need to switch branches on your end to 0.9.x and only work off there for now.

A PR would be appreciated to help steer people in the right direction for the time being.

@g3r4n when you fork and clone to your local, the default branch is master. You can do
git checkout -b 0.9.x and git pull origin 0.9.x or if you haven't clone yet git clone YOURFORKURL -b 0.9.x and make changes there, commit, and do git push origin 0.9.x
and do pull request from there.

@Timer I agree it's better to treat master as the currently released branch. Maybe after 0.10 ?

Timer commented

@viankakrisna yes after 0.10 we'll probably merge breaking changes into next, and leave master as current working-tree for released versions

@zperrault quick follow up to your comment here: #682 (comment)

Is the solution to run npm publish within the react-scripts folder? Or is there a different way you went about accomplishing the publish?

@gaearon
I want to create a common infrastructure for several live products of the same company. This infrastructure is supposed to be opinionated and contain common APIs, configurations and UI components based on our style guide.
Currently each one of the products has it's own different frontend infrastructure, and the company would like to create a standard for new products in the first stage, and in the next stage, replace existing components with the component pool from the new infrastructure.

After reading a lot of resources regarding CRA, I understand that if there is a good way to achieve it with React, it is probably forking the repository and keep merging it with the stable branch
as described in https://auth0.com/blog/how-to-configure-create-react-app/

In general, I want to enjoy the goodies that CRA has to offer and get updates for free, but in addition, I would like to impose usage of some additional "flavors" that all teams will use.

One method I thought about is to fork the repository as described, run create-react-app, and then add some common components and utilities of our company.
Each new product will be basically a clone of this repository and additional changes will be added for it's own requirements. We will frequently update the core (and the existing products) as react-scripts gets updated.

Looking at above I still cannot answer a number of questions:

  1. Do you think create-react-app will fit our requirements?
  2. If the answer is positive, is it a good idea to create such a common infrastructure in the first place? Wouldn't it be better if we will create a new project each time with create-react-app, and just add common modules using npm install?
  3. Can you name some of the disadvantages of the methods stated in (2)?

Thanks.

uqee commented

Have a look at my relevant article on Medium. Hope it helps as a starting point.

@Timer @viankakrisna

yes after 0.10 we'll probably merge breaking changes into next, and leave master as current working-tree for released versions

Can we have an update on this ? It seems that master still receive day to day udpdates.
The question behind is which source branch have to be used for maintaining a react-scripts fork ? (for now i'm still on the 0.9.x branch)

Timer commented

@romaindso we no longer will perform major react-scripts breakages on master, but this doesn't mean we won't update things daily on master. It should be safe to use again.

tl;dr maintain your fork off master.

@g3r4n did you every get it working? I am getting this error:

Error: Cannot find module 'react-dev-utils/browserHelper'

when trying to use the alpha for 2.0.0.

Is this still a viable solution/alternative to eject? How would I add a fork of react-scripts to an existing project created with CRA? The command line doesn't seem to update/overwrite configs in an existing project. Also, when starting anew I'm also getting Error: Cannot find module 'react-dev-utils/browsersHelper

I got it working. I had to publish forks of each package and had to update all internal references to point at my packages. Itโ€™s a pain but Iโ€™m just maintaining it until 2.0 drops officially. Unfortunately it has enough custom parts I cannot publish publicly but could contribute to your fork if you have a place you want to work out of.

Ouch! I see. Is there any way to update an existing project with a fork? We just started a project a couple of weeks ago via CRA and I need to make the smallest tweak to the webpack configs. I feel like I'm firing up a 747 just to visit my next door neighbor with this approach but I'm doing what I can to make things run.

Also, does each fork need to have its package name updated to be different from the official repo?

I saw this earlier and lost the link! Does it actually work? I'll have to give it a shot. Thanks!

By the way, that works like a charm, thanks!

What about https://github.com/timarney/react-app-rewired?

I agree react-app-rewired was a great solution before CRA2. But CRA2 uses webpack 4, which breaks most plugins. Also its maintainer is apparently retiring[1], so this remains a thorny problem.

  1. timarney/react-app-rewired#162

It seems that I have some trouble.
I forked thie repo and now its address is https://github.com/ubbcou/create-react-appใ€‚The directory of react-scripts is /packages/react-scriptsใ€‚
I want to use customized react-scripts (without publish in npm), but how can I install /packages/react-scripts ?
I only know that npm can install a repository like this: npm install --save https://github.com/ubbcou/create-react-app, and it can't do like this npm install --save https://github.com/ubbcou/create-react-app/packages/react-scripts.
what should I do???

uqee commented

@ubbcou publish it as a scoped package, like @ubbcou/react-scripts

@ubbcou ๅฐ†ๅฎƒไฝœไธบไธ€ไธช่Œƒๅ›ดๅŒ…ๅ‘ๅธƒ๏ผŒๅฐฑๅƒ@ubbcou/react-scripts

@uqee
Thank you :)
So.... if I have two or more different configurations, I should publish multiple @ubbcou/react-scripts-whatever ?

I tried to use a fork of react-scripts with yarn link but yarn build outputs to node_modules/create-react-app/build instead of MY_CURRENT_PROJECT/build. Are there any known problems that prevent using react-scripts from yarn link?

Well, after diving into the code, I noticed that there paths.js module that exports different path values based on some assumptions, one of them being published, for which it tries to evaluate if the app's node_modules contains the react-scripts package, but apparently this doesn't work with symlinks created with yarn link.

So what I've done to avoid publishing to npm each time I wanted to try something in my app, was to install my custom react-scripts from my file system with the following command:

yarn add file:/Users/hisa/workspace/create-react-app/packages/react-scripts/

This works, but the downside is that you have to run the command each time you make a modification of the your custom react-scripts. It would be awesome if we could use yarn link instead.