facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.69k stars 26.84k forks source link

checkForLatestVersion() in createReactApp.js dos not respect npm registry config setting #13518

Open wilee8 opened 8 months ago

wilee8 commented 8 months ago

https://github.com/facebook/create-react-app/blob/0a827f69ab0d2ee3871ba9b71350031d8a81b7ae/packages/create-react-app/createReactApp.js#L1101

On our internal network, we have to configure npm to use the local npm registry mirror: npm config set registry <mirror-url>

After setting the npm registry, I tried to create a new React app using create-react-app, but I have the following errors

$ npx create-react-app frontend
Need to install the following packages:
create-react-app@5.0.1
Ok to proceed? (y) y
undefined:1
<html>
^

SyntaxError: Unexpected token '<', "<html>
<he"... is not valid JSON
    at JSON.parse (<anonymous>)
    at IncomingMessage.<anonymous> (/home/wilee8/.npm/_npx/c67e74de0542c87c/node_modules/create-react-app/createReactApp.js:1109:28)
    at IncomingMessage.emit (node:events:526:35)
    at endReadableNT (node:internal/streams/readable:1408:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Node.js v20.9.0

I opened the createReactApp.js file at the location in the error, and opened it to line 1109. It was checkForLatestVersion(), the resolve(JSON.parse(body).latest); line:

function checkForLatestVersion() {                                                                                                                                                                                                                                                                                                                                
  return new Promise((resolve, reject) => {                                                                                                                                                                                                                                                                                                                       
    https                                                                                                                                                                                                                                                                                                                                                         
      .get(                                                                                                                                                                                                                                                                                                                                                       
        'https://registry.npmjs.org/-/package/create-react-app/dist-tags',                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        res => {                                                                                                                                                                                                                                                                                                                                                  
          if (res.statusCode === 200) {                                                                                                                                                                                                                                                                                                                           
            let body = '';                                                                                                                                                                                                                                                                                                                                        
            res.on('data', data => (body += data));                                                                                                                                                                                                                                                                                                               
            res.on('end', () => {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
              resolve(JSON.parse(body).latest);                                                                                                                                                                                                                                                                                                                   
            });                                                                                                                                                                                                                                                                                                                                                   
          } else {                                                                                                                                                                                                                                                                                                                                                
            reject();                                                                                                                                                                                                                                                                                                                                             
          }                                                                                                                                                                                                                                                                                                                                                       
        }                                                                                                                                                                                                                                                                                                                                                         
      )                                                                                                                                                                                                                                                                                                                                                           
      .on('error', () => {                                                                                                                                                                                                                                                                                                                                        
        reject();                                                                                                                                                                                                                                                                                                                                                 
      });                                                                                                                                                                                                                                                                                                                                                         
  });                                                                                                                                                                                                                                                                                                                                                             
}   

I added a console.log(body); line before the JSON.parse() call and ran create-react-app again. It failed again, with the console.log() line showing that it was receiving an HTML error page instead of the expected JSON. This is just the header, which should make it clear:

<html>
<head>
<title>BIG-IP Per Request Policy Resource blocked page</title>
<style>
...

I've ran into this issue with Docker before - we get blocked by registries and need to use our internal mirror. Which I have configured npm to use, but checkForLatestVersion() seems to be hard-coded to use the default (external) registry.

I modified checkForLatestVersion() to use the mirror URL instead:

      .get(                                                                                                                                                                                                                                                                                                                                                       
        //'https://registry.npmjs.org/-/package/create-react-app/dist-tags',                                                                                                                                                                                                                                                                                      
        '<mirror-url>-/package/create-react-app/dist-tags',                                                                                                                                                                                                                                                                 
        res => { 

And then create-react-app worked.

I think checkForLatestVersion() needs to be modified to check the registry setting in npm and use that URL instead of being hard-coded to use npmjs.org. Stealing some code from getProxy(), I came up with this:

function checkForLatestVersion() {                                                                                                                                                                                                                                                                                                                                
  return new Promise((resolve, reject) => {                                                                                                                                                                                                                                                                                                                       
    let registryURL = execSync('npm config get registry').toString().trim();                                                                                                                                                                                                                                                                                      
    let tagsURL = registryURL + '-/package/create-react-app/dist-tags';                                                                                                                                                                                                                                                                                           
    https                                                                                                                                                                                                                                                                                                                                                         
      .get(
        tagsURL,                                                                                                                                                                                                                                                                                                                                                  
        res => {                                                                                                                                                                                                                                                                                                                                                  
          if (res.statusCode === 200) {                                                                                                                                                                                                                                                                                                                           
            let body = '';                                                                                                                                                                                                                                                                                                                                        
            res.on('data', data => (body += data));                                                                                                                                                                                                                                                                                                               
            res.on('end', () => {                                                                                                                                                                                                                                                                                                                                 
              resolve(JSON.parse(body).latest);                                                                                                                                                                                                                                                                                                                   
            });                                                                                                                                                                                                                                                                                                                                                   
          } else {                                                                                                                                                                                                                                                                                                                                                
            reject();                                                                                                                                                                                                                                                                                                                                             
          }                                                                                                                                                                                                                                                                                                                                                       
        }                                                                                                                                                                                                                                                                                                                                                         
      )                                                                                                                                                                                                                                                                                                                                                           
      .on('error', () => {                                                                                                                                                                                                                                                                                                                                        
        reject();                                                                                                                                                                                                                                                                                                                                                 
      });                                                                                                                                                                                                                                                                                                                                                         
  });                                                                                                                                                                                                                                                                                                                                                             
} 

npm config get registry returns https://registry.npmjs.org/ if no value is set for registry in the npm config, so this should work whether or not someone configures npm to use a registry mirror.

sreeragdas commented 8 months ago

hi , can i work on this?