34

I have a single .json file that contains configuration stuff that I would like to reference from another script file using the typical import/require syntax. Currently I'm using webpack to resolve these dependencies and bundle them for me. This file however I want to be loaded at runtime and was hoping that there might be some type of loader that could resolve and load this file for me at runtime. So far I haven't found anything that matches my needs exactly.

Example:

var jQuery = require('jQuery');
var sol = require('some-other-lib');
var myConfig = require('/real/production/url/myconfig.json');

console.log(myConfig.myFavoriteSetting);

In the example above I'd like to have myconfig.json resolved and loaded at runtime.

Possibly related questions:

Community
  • 1
  • 1
jpierson
  • 16,435
  • 14
  • 105
  • 149
  • 1
    I've searched for similar stuff, but haven't found any loader. Eventually I used jquery getJSON function for that. – VyvIT Jan 15 '16 at 14:49
  • I've made the same workaround currently. Perhaps this is more simplistic in the long run as well. – jpierson Jan 17 '16 at 04:26
  • I am curious on how you were able to get this working even with the jquery getJSON? I seem to get a 404 that the config file does not exist although it is in the dist folder. – Thomas Vincent Blomberg Sep 19 '16 at 15:00
  • 1
    Added feature request to webpack. https://github.com/webpack/webpack/issues/5984 – mauron85 Nov 19 '17 at 10:22

5 Answers5

7

I think what you want is require.ensure, webpack's code splitting. The modules that you 'ensure' are put into a separate bundle, and when your 'ensure' executes at runtime, the webpack runtime automatically fetches the bundle via ajax. Note the callback syntax for ensure -- your callback runs when the bundle has finished loading. You still need to require the desired modules at that point; .ensure just makes sure they're available.

Code splitting is one of webpack's major features, it lets you load only what you need at any given time. There's plugins etc. to optimize the multiple bundles as well.

Brendan Gannon
  • 2,632
  • 15
  • 22
  • 3
    The use of require.ensure comes close but I supposed what I was looking for was something a little more along the lines of how *async/await* can split a function in half so that the second half runs as a continuation without having to change the synchronous style of the code. If a feature like this doesn't exist yet though I think your answer is probably the best I'm going to get. – jpierson Feb 01 '16 at 20:29
5

With Webpack 2, you can use System.import. It uses the Promise API. AFAIK, currently there's no way to have async/await code run in the browser. I believe Babel can only transpile async/await down to ES2015 so only the latest version of Node (v6.x) can run it. I don't think browsers are capable of understanding it yet because the transpiled code uses generators.

For System.import please note that some older browsers (IE 11 and below I believe) will require you to polyfill the Promise API. Check out polyfill.io for that.

If you REALLY want to use async/await in the browser, you might be able to do a full polyfill for ES2015.

wlingke
  • 4,699
  • 4
  • 36
  • 52
  • Yes, I probably should have more clearly stated that I was looking for an async approach that uses callbacks, promises, generators, or something that I could wrap async await around. In my case I was already using Babel as well as TypeScript to manage some of these types of async handling features. – jpierson Aug 11 '17 at 15:25
3

I had the same case with a file (config.json).

I decided to copy it with Copy-Webpack-Plugin

new CopyWebpackPlugin([
    // Copy directory contents to {output}/
    { from: 'config.json' }
  ]) 

After that, my file was in the output build directory. I used 'externals' property to reference my file in my webpack.config file :

  externals: {
    'config': "require('./config.json')"
  }

In my js file which load the config.json :

import config from 'config'

'config' load require('./config.json) which is the one in the output build directory.

I know it's tricky but I didn't find another solution to my problem. Maybe it will help someone.

EDIT

I had to use webpack in order to build because import config from 'config' wasn't understandable without it. That's why I replace :

externals: {
    './config.json': "require('./config.json')"
  }

and

var config = require('./config.json') //replace import config from 'config'

Without webpack, Javascript understand var config = require('./config.json') because it's the right path.

And when I build with webpack, it change by require('./config.json') when it sees './config.json', so it works

PestoP
  • 247
  • 2
  • 11
  • I can't seem to get this to work. Wouldn't Webpack search for config.json in the same folder as the webpack.config.js (because of the './config.json' reference) when building in development? Mine just throws a module not found for config.json since it's somewhere else with JS files in the dev setup. – Tru Sep 14 '17 at 05:58
  • You are right, if I want to run my server, I have to do it in the build folder. Webpack build my server folder in build/index.js. My folder is like this : build folder --> config.json and index.js (after webpack, there is a `require('./config.json')` in index.js uglified). server folder --> config.json and index.js (but in the index.js, I have `import config from 'config'` and node doesn't understand that..) – PestoP Sep 15 '17 at 15:46
  • I am trying to do something similar, I have a config file setup as an external using: `'settings': "require('./config.json')"` but `require` is not available in the browser and I am getting `Uncaught ReferenceError: require is not defined` any ideas? Is your working code available on github? – waxingsatirical Nov 13 '19 at 09:37
1

The behavior that I was originally looking for now seems to be described under the feature called Lazy Loading. The feature leverages Dynamic Imports as a replacement for the previously used require.ensure way of importing dynamic resources.

Since I don't have a example of my own to share here I'll leave this answer open as a Community Wiki answer for anybody else who would like to contribute one.

jpierson
  • 16,435
  • 14
  • 105
  • 149
-3

For Webpack 5:

Assume you need to load a config file at runtime. File config.json:

{
    "secret": "xxxccccvvvvXXXCCCVVV",
    "password": "1234567890"
}

And in your webpack.(config|common|prod|dev).js file:

const configFile = require('./path/to/your/config.json');
const { DefinePlugin } = require('webpack');
// ...rest of imports

function getConfig() { // Maybe move to a helper directory *shrugs*
   return JSON.stringify(configFile);
}

module.exports = {
...(rest of webpack configuration)

   plugins: [
      new DefinePlugin({
         common_config: DefinePlugin.runtimeValue(getConfig, true)
      })
   ]
}

Finally, if you use eslint, add this so the compiler doesn't complain:

"globals": {
   "common_config": "readonly"
}

Now in your app, you have access to common_config at all times (no imports needed)

KT-mongo
  • 2,044
  • 4
  • 18
  • 28
  • This is at build time not at runtime. – Jean F. Apr 06 '21 at 22:59
  • I wonder, did you try it out and it didn't work at runtime for you? Or you just saw the name of the property being `runtimeValue` and you said: "That's got a be a build time variable". Now please retract your negative comment as this is a working implementation on a current running app – KT-mongo Apr 06 '21 at 23:51
  • 2
    @Kleo This does **not** work at runtime. For example using: `DefinePlugin.runtimeValue(() => JSON.stringify({secret: process.env.MY_SECRET}), true)` I cannot use `window.common_config.secret` to obtain the value of the environment variable of the webserver. runtimeValue simply means that it autowatches values on build, but it **still** not a runtime solution. Runtime solution means you create the bundle with webpack, you move the bundle into a nginx docker container and the javascript code should be able to use, for example, the webserver environment variables. – GACy20 Apr 16 '21 at 13:52
  • Who said anything about window? Where did I mention anywhere the window object, or who did mention the window object in this question? This is where things get out of hand, when you mention something that I didn't reference whatsoever. Then you say: runtimeValue simply means that it autowatches values on build. Can you please explainn where is this written? What confuses me is, that how 2 of you claiming a property called `runtimeValue` is a build value and provide no proof, even though I did through a script. Run that webpack config and prove it through code that this isn't runtime please. – KT-mongo Apr 18 '21 at 10:20
  • Sorry @Kleo, I think the others may be right. Of course I haven't tested it yet but just based on the documentation it sounds like the "runtime" that webpack may be referring to is the server runtime during while the build process is watching source files. https://webpack.js.org/plugins/define-plugin/#runtime-values-via-runtimevalue – jpierson Aug 02 '22 at 17:05