2

I am using react-scripts in my project. I use some newer syntax that requires my webpack.config use plugins such as

plugins: ['transform-decorators-legacy']

I am trying to avoid ejecting the config files just to add this line to the webpack.config.dev and webpack.config.prod files.

So I am trying to make a script to insert this automatically.

In the dev file, I need to insert it after the cacheDirectory: true.

 // Process JS with Babel.
  {
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: 'babel',
    query: {
      // @remove-on-eject-begin
      babelrc: false,
      presets: [require.resolve('babel-preset-react-app')],
      // @remove-on-eject-end
      // This is a feature of `babel-loader` for webpack (not Babel itself).
      // It enables caching results in ./node_modules/.cache/babel-loader/
      // directory for faster rebuilds.
      cacheDirectory: true
    }
  }

And I have come up with this to insert it

"fix-react-scripts-dev": "ex -sc '%s/cacheDirectory: true/cacheDirectory: true,plugins: ['transform-decorators-legacy']/g|x' node_modules/react-scripts/config/webpack.config.dev.js"

The result is

  {
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: 'babel',
    query: {
      // @remove-on-eject-begin
      babelrc: false,
      presets: [require.resolve('babel-preset-react-app')],
      // @remove-on-eject-end
      // This is a feature of `babel-loader` for webpack (not Babel itself).
      // It enables caching results in ./node_modules/.cache/babel-loader/
      // directory for faster rebuilds.
      cacheDirectory: true,
      plugins: [transform-decorators-legacy]
    }
  }

the problem is

plugins: [transform-decorators-legacy]

is missing the quotation marks. Is this a character escape issue I am missing from my script?

And for the prod config file. I need to insert it after

presets: [require.resolve('babel-preset-react-app')]

// Process JS with Babel.
  {
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: 'babel',
    // @remove-on-eject-begin
    query: {
      babelrc: false,
      presets: [require.resolve('babel-preset-react-app')]
    }
    // @remove-on-eject-end
  }
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
texas697
  • 5,609
  • 16
  • 65
  • 131

1 Answers1

2

The problem with your script is that you're ending the command string with the single quotes. This isn't an issue to bash since it'll just treat the rest of the string as an unquoted string until the second single quote reopens a single quoted string. However, the preferred method to escape single quotes in bash also interrupts the JSON string! You need an escape sequence that escapes single quotes in a single quoted string with escaped double quotes. That ends up being '\"'\"'. This ends the first string, starts a double quoted string that doesn't end the JSON string, enters a single quote, ends the double quoted string without ending the JSON string, and starts another single quoted string. So, your script becomes:

"fix-react-scripts-dev": "ex -sc '%s/cacheDirectory: true/cacheDirectory: true,plugins: ['\"'\"'transform-decorators-legacy'\"'\"']/g|x' node_modules/react-scripts/config/webpack.config.dev.js"

As for the second part, I'm just going to assume you made a typo by putting presets in there twice since it wouldn't make sense for it to be outside the code block. If this is true then the plugins line needs to go underneath the presets line in the query. If this assumption was wrong please let me know.

This needs a similar super-escape sequence for the single quotes but there's another issue with matching the presets line. This line not only has single quotes but also has square brackets. Those also need to be escaped or else the dashes inside them will be considered part of a range search in the search pattern of %s (think how you can do [a-z] in regex, vim allows this in the search pattern). Your prod script would then be (change the directory if needed):

"fix-react-scripts-prod": "ex -sc '%s/presets: \\[require.resolve('\"'\"'babel\\-preset\\-react\\-app'\"'\"')\\]/presets: \\[require.resolve('\"'\"'babel\\-preset\\-react\\-app'\"'\"')\\],plugins: \\['\"'\"'transform\\-decorators\\-legacy'\"'\"'\\]/g|x' node_modules/react-scripts/config/webpack.config.prod.js"
Community
  • 1
  • 1
Peter G
  • 2,773
  • 3
  • 25
  • 35