0

The question: Why won't import parse my JSON string provided as a webpack externals member?

I have a group of React apps that need to share a JSON configuration file, which I want webpack (v4) to inline into each app during the build. Based on answers like this and similar examples like the "Using Webpack" section in this article, it looks like this should work, but the JSON string imports as a string value, it is not parsed into an object.

JSON:

{ "api": "https://localhost:5050/api" }

Webpack (modifying a config produced by another package):

config.externals.push({
  'AppConfig': JSON.stringify(require(path.resolve(configPath, "app-config.json")))
});

Module:

import Config from 'AppConfig'; 

I'm using a component to read the OpenAPI schema:

<ApiService schema={Config.api}> ...

The error shows the JSON is not parsed, it is imported as a string literal:

GET https://localhost:9000/%7B%22api%22:%22https://localhost:5050/api%22%7D net::ERR_ABORTED 404
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The webpack config works, obviously. And I know the configuration itself is good, if I change the import to reference the JSON file directly, it works as expected. But that requires using lots of ../../../ relative path garbage I'm trying to avoid. I am also not interested in the export default approach in a .js file that I've seen people use for similar questions.

Am I missing a webpack or Babel plug-in somewhere, perhaps?

McGuireV10
  • 9,572
  • 5
  • 48
  • 64
  • 1
    What if you wrote a `resolve.alias` against a module somewhere in a good place that imports the JSON file? That would avoid the problem of relative paths while giving you a single place in the codebase where to manage configuration. There are other ways too but I have a feeling this could fit your use case well. – Juho Vepsäläinen Jan 22 '21 at 15:03
  • @JuhoVepsäläinen Someone over in the webpack repo just suggested the same thing. I had tried using `path.resolve` and `path.relative` with `exports` but for some reason that results in trying to read the file from the server at runtime as a module, which doesn't work out well. But I'll definitely give `alias` a shot at work on Monday. Thanks. – McGuireV10 Jan 22 '21 at 16:19

1 Answers1

0

The solution is to use an alias with a relative path. The extra path steps are because this is in a utility module.exports that modifies an existing webpack configuration object. The npm_config_top_dir environment variable is specific to our monorepo setup (Lerna runs these scripts and the shared config file is in that root directory).

const pathToCallerSourceCode = path.resolve(process.cwd(), "./src");
const appConfigFullPathname = path.resolve(process.env.npm_config_top_dir, "app-config.json");
const appConfigRelativePathname = path.relative(pathToCallerSourceCode, appConfigFullPathname);

Object.assign(config.resolve, { alias: { AppConfig: appConfigRelativePathname }});
McGuireV10
  • 9,572
  • 5
  • 48
  • 64