react-locale-hot-switch
react-locale-hot-switch copied to clipboard
Issue with Safari, require.ensure
Thanks for this great example. I've issues making it work in my own code. Consider:
if (!global.Intl) {
require.ensure([
'intl/Intl',
'intl/locale-data/jsonp/en.js'
], function (require) {
require('intl/Intl');
require('intl/locale-data/jsonp/en.js');
});
}
var React = require('react/addons');
var ReactIntl = require('react-intl');
Using require.ensure moves the intl code in a separate chunk (say, 1.1.js). However, react and react-intl go in another chunk (in my case, vendor.js). In my index.html, I load vendor.js, then an app.js with my own code, and bootstrap React. Safari groaks though:
ReferenceError: Can't find variable: Intl
Safari's error points at a line found in react-intl/lib/mixins.js:
exports["default"] = {
[...]
getNumberFormat : intl$format$cache$$["default"](Intl.NumberFormat),
It seems that this line is evaluated when the vendor.js chunk is loaded, but the call to require.ensure has not completed yet, and Intl.NumberFormat is not defined.
This is puzzling me because I thought require.ensure was synchronous -- the doc states:
require.ensure(dependencies, callback):
The require.ensure method ensures that every dependency in dependencies can be synchronously required when calling the callback.
I might have misunderstood that, either way if it's loaded asynchronously in your example, then the chunk that requires react-intl has to be as well, and happen after? How do you ensure that is not clear to me.
Thanks
Hi @sebastienbarre thanks for reporting this. With require.ensure, dependencies are synchronous in the callback. So, if react-intl needs Intl in order to be required, you should move the modules requiring it in the require.ensure callback.
(maybe the react-intl version I used in this project didn't need Intl in the global scope yet).
I'd move the require('./App.js') in the callback: client.js should be written as
var React = require('react');
var i18nLoader = require('./i18n');
function renderApp(i18n) {
// here we have Intl
var App = require('./App.js');
React.render(<App {...i18n} />, document.body);
}
var defaultLocale = document.documentElement.getAttribute('lang');
i18nLoader(defaultLocale, renderApp);
I've updated the dependencies to reproduce the problem – which has been fixed with 441f6b8.
Thanks a lot @gpbl for looking into this so quick. I've replied in the other thread, yahoo/react-intl#39. My issue here, from a performance perspective, is that webpack is going to create a separate chunk for these 3 pieces. You need to run client.js first, which might trigger either a require.ensure on Intl followed by a require on app.js in the same synchronous callback, or just a require on app.js if we have Intl already. It seems to me that these 3 pieces can not reliably be in the same chunk, thus requiring 3 round-trips. Previously we could get by with 2 round-trips. Not a huge deal but I figured I would raise that point, since that change in react-intl had that side-effect. Thanks.
I understand you have only one specific route needing it, which is also a very special case: react-intl doesn't fit well because since it shims something that should be always available.