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
Fixes #24570 - [JS] add dynamic import #5934
Conversation
Issues: #24570 |
I'm concerned this will cause parts of libraries that aren't used by core but needed for plugins to be missing from vendor.js and cause plugins to break. |
publicPath = process.env.ASSET_PATH || '/webpack/'; | ||
} else { | ||
publicPath = process.env.ASSET_PATH || `http://${devServerHostname}:${devServerPort}/webpack/`; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, can be written as:
publicPath = process.env.ASSET_PATH || (production ? '/webpack/' : `http://${devServerHostname}:${devServerPort}/webpack/`);
but why is it needed? (or maybe it should be a separate PR?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it needed for webpackChunkName, otherwise on develop env the splitted js won't be reachable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't find any better way for that than what Amir has here.
I wonder if we can somehow guess http
vs https
from config. That would make it smoother. But I'm fine with the code as is if we can't find it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@amirfefer I found it! We can use process.argv.includes('--https')
@@ -12,10 +12,12 @@ | |||
"axios-mock-adapter": "^1.10.0", | |||
"babel-cli": "^6.10.1", | |||
"babel-core": "^6.26.3", | |||
"babel-eslint": "^6.1.2", | |||
"babel-eslint": "^7.2.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this required for this PR?
import CommonForm from '../common/forms/CommonForm'; | ||
|
||
import './PasswordStrength.scss'; | ||
|
||
const LoadingComponent = () => <div> Loading... </div>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe use our Loader component? at least, the spinner from it (note text is also not extracted)
@amirfefer It turns out i did start writing something similar before, can you review ohadlevy@4a33ba7? thanks! |
Why? if a plugin import a component, it would simply have a webpack generated code to load it on demand, AFAIU it should be 100% comparable with current state.
I guess it depends, does it make sense to load an extra 1MB that is used in only one page? (e.g. password strength), I believe the best practice today is to split, and load on demand, sometimes with |
I've tested
we can use
as long as the javascript stack becomes bigger - then it would be better to use code splitting as it recommended by webpack. |
of course it doesn't exist in vendor, its not in its own file? good to know Katello works as expected. |
@amirfefer did you test it with an RPM build or just in development? following the issues we've had i'd be very worried about the vendor.js file not including some code plugins expect it to include. I'm not really worried about a few hundred KBs in download size. Most of our users are connected over fast local ethernet, so there's no big difference in time, and anyways it should only be downloaded once and cached afterwards, so I don't see how this benefits us. I expect if they have to wait for another download when, in this example, editing a user - it would give worse user experience. We've had this discussion before (when we were talking about page-specific js code), and we decided to try and push everything into application.js and remove the page-specific files. I'm wondering what changed. Keep in mind that webpack's recommended practices are written with SaaS in mind. In that case, you need to provide resources over sometimes slow connections, reduce network costs, and have complete control of their stack - non of which is true for foreman. |
@@ -11,10 +11,21 @@ var LodashModuleReplacementPlugin = require('lodash-webpack-plugin'); | |||
var pluginUtils = require('../script/plugin_webpack_directories'); | |||
var vendorEntry = require('./webpack.vendor'); | |||
var SimpleNamedModulesPlugin = require('../webpack/simple_named_modules'); | |||
var { execSync } = require('child_process'); | |||
|
|||
const getHostname = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to call the argument bindhost instead of hostname (to alignt to rails, webpack etc).
also, in order to get the hostname in node, please use something like
var os = require('os');
const devServerHostname = process.env.HOSTNAME || os.hostname();
@tbrisker |
@amirfefer did you compile vendor.js separately without katello, then used that with katello that built its own bundle when testing? Or did you just compile all assets together? |
if (production) { | ||
publicPath = process.env.ASSET_PATH || '/webpack/'; | ||
} else { | ||
publicPath = process.env.ASSET_PATH || `http://${devServerHostname}:${devServerPort}/webpack/`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that in the Katello development setup we run with https
I just want to agree with @amirfefer and @ohadlevy on this (sorry @tbrisker 😄). I think that this is a good change as long as plugins also have a way to require the necessary libraries and we document that this needs to be done. |
I agree with moving less frequently used code to separate chunks. Prefetch should cover concerns about certain pages being slowed down. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel like my concerns were properly addressed.
No one has confirmed this won't break plugins on packaged installs. Plugins may expect certain libraries to be available in the vendor.js file, which this will remove (right now just pw strength, but if i understand correctly the aim is to have multiple such libraries). Considering the amount of issues we've had around this exact area so far, i'd be very wary of introducing changes that aren't properly tested on a packaged build.
Additionally, no one has explained why we decided to change direction from trying to load all JS in one big chunk once to loading additional files on certain pages, which will require re-rendering those pages once the new JS is loaded leading to a feeling of slower load times. In fact, the argument was made that we should move to SPA (among other reasons) in order to reduce the number of server round-trips needed before a page can be properly displayed.
I don't think saving a few hundred kb's in the production assets size, which is downloaded once over a usually very fast connection, is worth the risk and tradeoffs here, and haven't been convinced yet of what value this actually brings other than a bit smaller vendor bundle. So, all in all, for me this is currently a 👎 .
closing this for now, |
some modules (such as brace, password-strength...) takes a large cut from the bundle/vendor file.
this solution imports these modules dynamically on demand with react-loadable
Production vendor file without dynamic import
Production vendor file with dynamic import (password-strength only)