Search code examples
javascriptnode.jswebpackpug-loader

Pass asynchronously loaded data to pug-html-loader in webpack


General setup

I am building a small website with webpack and pug based on this awesome boilerplate: https://github.com/alexnoz/webpack-pug-scss-boilerplate.git

The project is up and running and I am able to render pug files correctly.

Requirement

Now I need to load some data before all the webpack compiling happens. I want to pass that data to the pug-html-loader as described in this answered question.

Problem/Question

My problem is, that I have to load that data asynchronically. So what I have is a Promise. How can I make sure that the promise is finished before webpack compile happens?

This is my current aproach that doesn't work

// in webpack.config.js

var myData = []
loadSomeDataAsync().then(loadedData => myData = loadedData)

{
  loader: 'pug-html-loader',
  options: {
    data: myData    // <==== 
  }
}

pug-html-loader accepts the options.data If I put static data there, then this data is available inside the pug template.

I know that my problem seems to be, that my Promise is not yet resolved, before the webpack compile happens. But how can get webpack to somehow "wait" for the Promise to resolve?

I already tried to register webpack event hooks. But did not succeed. Any further suggestions?


Solution

  • As simple as that:

    module.exports = () => {
      return loadSomeDataAsync().then(function(loadedData) {
    
            return {
              entry:  './app.js',
              ...
              options {
                data: loadedData
              }
              ...
            }
      });
    };
    

    Note that the setTimeout() in the documentation is for illustration purposes (to simulate a delay while fetching data).

    How is it waiting? Internally, they must be using async + await.

    For example, to help you better understand, look at this code (again, for illustration purposes):

    function simulateLoadData() { 
      return new Promise(resolve => {
        setTimeout(() => {
          resolve("data"); // once I get the data, I pass it through resolve
        }, 2000); // just for illustration purposes and simulate query to remote machine
      });
    }
    
    function getConfig() {
      return simulateLoadData().then(function(dataLoaded){ // here I retrieve the data resolved
        return { data: dataLoaded }; // I can pass dataLoaded to my config
      });
    }
    
    async function app() {
        var config = await getConfig(); // here is where I retrieve the returned config
        console.log("config", config); // config > Object { data: "data" } 
    }
    
    app();