Skip to content
This repository has been archived by the owner on Apr 5, 2021. It is now read-only.

when multiple html files are import external automatically according to the import situation #21

Open
sanwv opened this issue Sep 30, 2017 · 5 comments

Comments

@sanwv
Copy link

sanwv commented Sep 30, 2017

Usually an application will have a lot of pages, so it is not possible to use files specify a page will append which external resource. if have a way to import externals automatically according import situcation in src files.

for example, one file (admin.html) need react,moment, another only need react(help.html). i configed all externals in plugin options. in build file, admin.html have react,moment scripts and help.html only react script.

this is me how to config webpack entry and html-webpack-plugin:

var pages = glob.sync('*.page.js', {cwd: cwd + '/src/pages', matchBase: true});
var entry = {};
var htmls = [];
pages.forEach((item) => {
    let chunk = 'pages/' + item.slice(0, 0 - '.page.js'.length);
    entry[chunk] = ['./src/pages/' + item];
    htmls.push(new HtmlWebpackPlugin({
        filename: path.resolve('./build') + '/' + item.slice(0, 0 - '.page.js'.length) + '.html',
        template: path.resolve(cwd, 'src/htmls/index.html'),
        chunks: [chunk],
        hash: true
    }))
});
//... more code
@mmiller42
Copy link
Owner

I would expect that you could do the same thing with the externals plugin:

var pages = glob.sync('*.page.js', {cwd: cwd + '/src/pages', matchBase: true});
var entry = {};
var htmls = [];
var externalsPlugins = [];
var externalsByPage = {
  'help.html': [
    { module: 'react', entry: 'dist/react.min.js', global: 'React' },
    { module: 'react-dom', entry: 'dist/react-dom.min.js', global: 'ReactDOM' }
  ],
  'admin.html': [
    { module: 'react', entry: 'dist/react.min.js', global: 'React' },
    { module: 'react-dom', entry: 'dist/react-dom.min.js', global: 'ReactDOM' },
    { module: 'moment', entry: 'moment.js', global: 'moment' }
  ]
};

pages.forEach((item) => {
    let chunk = 'pages/' + item.slice(0, 0 - '.page.js'.length);
    entry[chunk] = ['./src/pages/' + item];
    var filename = path.resolve('./build') + '/' + item.slice(0, 0 - '.page.js'.length) + '.html';
    htmls.push(new HtmlWebpackPlugin({
        filename: filename,
        template: path.resolve(cwd, 'src/htmls/index.html'),
        chunks: [chunk],
        hash: true
    }))
    externalsPlugins.push(new HtmlWebpackExternalsPlugin({
      externals: externalsByPage[filename],
      files: filename
    }));
});

webpackConfig.plugins = webpackConfig.plugins.concat(htmls, externalsPlugins);

@sanwv
Copy link
Author

sanwv commented Sep 30, 2017

Yes, but when we have hundreds of pages,more than twenty packages ,the way will be troublesome and config file too length. Not perfect

in the question,i also got the way like your, the README is very detailed。 in fact ,we can also directly written in the html webpack plugin template.

Can you only define an external module list, according to the degree of dependence on a page automatically import the required external?

@sanwv
Copy link
Author

sanwv commented Sep 30, 2017

like webpack ‘externals’ config is a map for all entry,
loaded on demand

@mmiller42
Copy link
Owner

I am not sure if this is possible. It is something I will look into. I think that HtmlWebpackPlugin has already generated the HTML output before Webpack has generated a full list of all packages that are imported.

@sanwv
Copy link
Author

sanwv commented Oct 7, 2017

I wrote a test plugin that seemed to get the result.

DepsPlugin.prototype.apply = function (compiler) {
    compiler.plugin('compilation', function (compilation) {


        compilation.plugin('html-webpack-plugin-before-html-processing', function (htmlPluginData, callback) {
            console.log('haha,enter again and again!');
            let externalDepMap = {};
            compilation.entries.forEach(entry => {
                let name = entry.name;
                externalDepMap[name] = [];
                entry.dependencies.forEach(dep => {//dep=SingleEntryDependency
                    dep.module.dependencies.forEach(_dep => {//_dep=[ConstDependency,CommonJsRequireDependency,RequireHeaderDependency,...]
                        if (_dep.module && _dep.module.external) {
                            externalDepMap[name].push(_dep.module.userRequest);
                        }
                    })

                });

            })
            console.log(externalDepMap);//externalDepMap maybe need be cached!
            console.log(Object.keys(htmlPluginData.assets.chunks)[0]);
            callback(null, htmlPluginData);
        });


    }.bind(this));
}

@mmiller42 mmiller42 self-assigned this Oct 26, 2017
@mmiller42 mmiller42 removed their assignment Feb 17, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants