Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow google closure self-managed js dynamic imports #72

Open
MorganDream opened this issue Nov 26, 2018 · 7 comments
Open

Allow google closure self-managed js dynamic imports #72

MorganDream opened this issue Nov 26, 2018 · 7 comments

Comments

@MorganDream
Copy link

Google Closure Library has a dynamic imports engine --- goog.module.ModuleManager, which can be used to lazy loading JS resource. This engine is different from webpack, thus it should be handled without webpackJsonp.

I have used ModuleManager successfully to realize JS lay loading with closure-webpack-plugin, only in case where entry chunks have no common dependence.
I have to use CommonChunksPlugin When entry chunks have common dependence, as mentioned in Readme. But webpack tries to handle child chunk(lazy loading chunk) with webpackJsonp, which will cause child chunk lazy loading failure. The reason is below:

if (parentChunk !== null) {
return `${defParts[0]}:webpackJsonp([${
chunk.id
}], function(__wpcc){%s});`;
} else if (chunk) {
return `${defParts[0]}:${entryChunkWrapper}`;
}

I suggest adding an option: entryChunks to use entryChunkWrapper instead of webpackJsonp.
Could you grant me pull request permission? I have done implemented it locally. @ChadKillingsworth

@ChadKillingsworth
Copy link
Member

@jplaisted Can you weigh in on this? I've not used ModuleManager. Should this be recognized by webpack as a potential split point for code splitting?

Could you grant me pull request permission

Anyone can make a pull request. You need to fork this repo, push changes to a branch there, then you can make a pull request to the main repo.

@jplaisted
Copy link
Contributor

Admittedly I know very little about this as well. AFAIK it is what we use for code splitting internally.

Rerouting to @concavelenz @shicks or @brad4d.

@brad4d
Copy link

brad4d commented Nov 29, 2018

@MorganDream

The section of code you referenced is part of the closure-webpack-plugin repository rather than the closure-compiler one. Which one of these repositories would your PR affect?

I think submitting a PR will be your best bet, here, since it'll make it clear exactly what you're doing.

Unfortunately most of us working on closure-compiler don't use webpack, so we don't have a good understanding of how it interacts with stuff like ModuleManager.

@MorganDream
Copy link
Author

MorganDream commented Nov 30, 2018

@ChadKillingsworth @brad4d Thanks for your response and instruction.
Yes I want to issue a PR, and my local solution is working for me.
But I am not sure if it is the best solution to add a config option.
ModuleManager lazy loading is working in NONE mode but not working in AggressiveBundle mode, in later mode, webpackJsonp is compiled to a function accepting 2 params instead of 3(I am using webpack 3). So I guess it is because webpackJsonp is compiled too aggressively that it is not working.

Update:
In AggressiveBundle mode, webpackJsonp is compiled to be

        var a = window.webpackJsonp;
        window.webpackJsonp = function(b, c) {
            var d, e = [];
            for (d = 0; d < b.length; d++)
                aa[b[d]] && (e.push(aa[b[d]][0]),
                aa[b[d]] = 0);
            for (a && a(b, function() {}); e.length; )
                e.shift()(c)
        }

According to

if (parentChunk !== null) {
return `${defParts[0]}:webpackJsonp([${
chunk.id
}], function(__wpcc){%s});`;
} else if (chunk) {

A child chunk function will be never be executed if aa is empty, which is my case.

Are you certain webpackJsonp will work in AggressiveBundle mode?
That is why I want to abort webpackJsonp wrapper in my PR, and it works well just regarding child chunk as entry chunks.

@ChadKillingsworth
Copy link
Member

Your entryChunks idea is creative - but not really in the spirit of how webpack works. Can you put up a demo using ModuleManager? That will help me understand exactly what the problem is.

I'm guessing it's because webpack doesn't recognize the call to lazy load a module. If that was recognized, it could be an automatic split point and then it would be clearer what needs to be fixed for webpack's runtime to load the module.

@MorganDream
Copy link
Author

MorganDream commented Dec 3, 2018

// A.js
TEST_MM = true;
goog.module.ModuleManager.getInstance().setLoaded('moduleA');
// main.js
var moduleManager = goog.module.ModuleManager.getInstance();
moduleManager.setLoader(new goog.module.ModuleLoader());
moduleManager.setAllModuleInfo({
    'moduleA': []
});
moduleManager.setModuleUris({
    'moduleA': 'http:url/to/your/compiled/A.js'
});
// lazy loading triggered by action
document.addEventListener('click', function(e){
    // this success callback is called after module loaded successfully
    // which is when moduleManager.setLoaded('moduleA') is executed
    // below process will load compiled A.js by XHR and then execute it
    moduleManager.execOnLoad('moduleA', function(){
        console.log(window.TEST_MM); // true
    });
});
// webpack.config.js
module.exports = {
    entry: {
        'main': 'path/to/main.js',
        'moduleA': 'path/to/A.js' 
    }
    ...
    plugins: [
        new ClosurePlugin({
           mode: 'AGGRESSIVE_BUNDLE', // in 'NONE' mode, this can work, but not in Aggressive_bundle
           ...
        }),
        // We extract common dependencies into main to avoid ClosurePlugin error, as you suggested
        // In this case, they don't have common dependencies
        // This will still establish a parent-child relationship between main and moduleA
        new webpack.optimize.CommonsChunkPlugin({
            name: 'main',
            minChunks: 2
        })
    ]
}

As moduleA is a child chunk, it will be wrapped with webpackJsonp and never executed even lazy loaded successfully. if A.js is not executed, setLoaded flag is never hitted, the success callback will never be executed.

@MorganDream
Copy link
Author

MorganDream commented Dec 7, 2018

After more investigation, I found that closure-webpack-plugin itself has a runtime file which will be included to compilation when chunk that has no runtime is included.
Through this runtime, you can manage dynamic imports in webpack style compatible with closure compiler(which I guess).
However, this is not compatible with goog.module.ModuleManager, which manage chunk info, url, downloading, executing and callback all by itself instead of webpack.

So I suggest adding an option runtimeNeedlessChunks to let ModuleManager manage the related chunks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants