Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 409
Robert Avatar asked Sep 16 '19 12:09

Robert


2 Answers

the default pattern for this situation looks like:

const configPromise = new Promise(function(resolve, reject) {
  setTimeout(() => { resolve(webpackConfig) }, 1000);
});

configPromise
  .then(webpack) // Passes the config to webpack
  .then(compiler => {
    // Do the work with the compiler
  });

The feature is well documented in DOCS.

Webpack will run the function exported by the configuration file and wait for a Promise to be returned. Handy when you need to asynchronously load configuration variables.

module.exports = () => {
  return new Promise((resolve, reject) => { // The promise could be an XHR call using fetch, Axios or whatever
    setTimeout(() => { 
      resolve({ // Resolve webpack config
        entry: './app.js',
        /* ... */
      });
    }, 5000);
  });
};
like image 58
Mosè Raguzzini Avatar answered Nov 10 '22 09:11

Mosè Raguzzini


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();
like image 1
jperl Avatar answered Nov 10 '22 09:11

jperl