webdiscus / html-bundler-webpack-plugin

Alternative to html-webpack-plugin ✅ Renders Eta, EJS, Handlebars, Nunjucks, Pug, Twig templates "out of the box" ✅ Resolves source files of scripts, styles, images in HTML ✅ Uses a template as entry point
ISC License
138 stars 14 forks source link

[FEATURE REQUEST] handlebars data accept a json file #9

Closed 5ulo closed 1 year ago

5ulo commented 1 year ago

Feature request

What is motivation or use case for adding/changing the behavior?

I'm migrating from HandlebarsPlugin to HtmlBundlerPlugin and I can't figure out how to pass data from data.json file to data entry. data accepts only object | null and does not accept path to json.

Describe the solution you'd like

Simple:

data: path.join(PATH_SRC, 'data.json'),

Describe alternatives you've considered

ATM the only alternative is to stick with webpack-handlebars-plugin where the configuration looks like this:

new HandlebarsPlugin({
    entry: path.join(PATH_PAGES, '!(assets|data|libs|hbs_helpers|layout|partials){,**/}*.hbs'),
    output: path.join(PATH_DIST, '[path]', '[name].html'), // is rewritten in getTargetFilepath
    data: path.join(PATH_SRC, 'data.json'),
    partials: [
        path.join(PATH_LAYOUT, '*.hbs'),
        path.resolve(PATH_PARTIALS, '*', '*.hbs')
    ],
    ...
}),

file data.json is also watched an works fine with HMR My current try with HtmlBundlerPlugin is this: data.json

{
    "foo": "bar"
}

webpack.config.js

new HtmlBundlerPlugin({
    entry: path.join(PATH_PAGES),
    loaderOptions: {
        preprocessor: 'handlebars', // enable Handlebars compiler
        data: path.join(PATH_SRC, 'data.json'), // {{foo}} returns nothing
        // data: {
        //     title: 'meh'
        // }, // {{title}} returns 'meh'
        preprocessorOptions: {},
    },
}),
webdiscus commented 1 year ago

Hello @5ulo

thanks for the question.

The HtmlBundlerPlugin was implemented independently from webpack-handlebars-plugin and has own options these must not be 100% compatible with webpack-handlebars-plugin options.

The data option is not a filename because it doesn't make sense:

  1. you can self load a JSON-file: data: require('/path/to/file.json')
  2. the file will be once required by plugin initialisation and after changes will not be re-readed, because the webpack configuration take changes only after stop/restart.

How often do you change the json file? If 1-2 times, you can stop/restart Webpack.

If to reload the json file after each change, it need to reinitialize the plugin and the Handlebars engine, which slows things down.

5ulo commented 1 year ago

Yeah that's the problem as the json holds data I change while I develop website. It's like dynamic database for me. For example creating new section - I just type data into json and they immediately show up in template. No need to stop/run whole webpack. The way you descibed (data required once) was the same functionality by handlebars-loader so then I moved on to webpack-handlebars-plugin. Now I was looking forward to use bundler and this one thing stopped me. edit: for imagination what my worflow is - I build html templates dynamically, so I write json data while I write hbs and make loops etc.. I'm not a webpack plugins programmer so I am curious why reinitialize plugin and hbs engine. My idea was to check the json path before compilation and update the data. I found this in the webpack-handlebars-plugin src https://github.com/sagold/handlebars-webpack-plugin/blob/master/index.js:

    /**
     * (Re)load input data for hbs rendering
     */
    updateData() {
        if (this.options.data && typeof this.options.data === "string") {
            try {
                const dataFromFile = JSON.parse(this.readFile(this.options.data));
                this.addDependency(this.options.data);
                this.data = dataFromFile;
            } catch (e) {
                console.error(`Tried to read ${this.options.data} as json-file and failed. Using it as data source...`);
                this.data = this.options.data;
            }
        } else {
            this.data = this.options.data;
        }
    }

and the the update() is called right at the top of compile:

    compileAllEntryFiles(compilation, done) {

        this.updateData();
webdiscus commented 1 year ago

@5ulo

It's like dynamic database for me.. I just type data into json and they immediately show up in template

Thanks for clarifying. Yes, then it makes sense to do a dynamic data update in the template.

I will to add new dataFile option for dynamically update data after changes. Cool feature. Thank you for the useful feature request.

I note this feature on the TODO list for one of the next releases (1-2 weeeks).

webdiscus commented 1 year ago

@5ulo

in new version 1.17.0 you can define the data option as an absolute or relative filename of a JSON or JS file. See the usage example by data option.

P.S. You can use data option in entry object to pass page specifically data.

5ulo commented 1 year ago
data: path.join(PATH_SRC, 'data.json'),

works like a charm!! you made my day :)