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

Include info on how to tree shake dynamically imported locales #34

Open
masives opened this issue Sep 18, 2018 · 9 comments
Open

Include info on how to tree shake dynamically imported locales #34

masives opened this issue Sep 18, 2018 · 9 comments

Comments

@masives
Copy link

masives commented Sep 18, 2018

If locale is required dynamically all languages in the date-fns are loaded into bundle (~160kb). However it is possible to use webpack to trim down the languages added to bundle using Context replacement plugin.

Usage example

const getLocale = (locale) => require(`date-fns/locale/${locale}/index.js`);

const formatDate = (date, formatStyle, locale) => {
    return format(date, formatStyle, {
        locale: getLocale(locale)
    });
};

Config example:

const supportedLocales = ["en", "de", "pl", "it"]
plugins: [
  new ContextReplacementPlugin(/date\-fns[\/\\]/, new RegExp(`[/\\\\\](${supportedLocales.join('|')})[/\\\\\]`)),
]

This results in a language bundle of ~23kb.

@stevemao
Copy link
Member

stevemao commented Sep 18, 2018

Why don't you use static import for this?

import enLocale from 'date-fns/locale/en'
import deLocale from 'date-fns/locale/de'
...

@andrew-yangy
Copy link
Member

andrew-yangy commented Sep 19, 2018

You can try with the webpack dynamic import:

const formatDate = async (date, formatStyle, locale) => {
    const localeFile = await import(/* webpackChunkName: "locale-[request]" */ `date-fns/locale/${locale}`);
    return format(date, formatStyle, {locale: localeFile});
}

@stevemao
Copy link
Member

dynamic import would be the same as require and you have to manually exclude the script.

@stevemao
Copy link
Member

BTW, your example doesn't involve tree shaking. Just inclusion/exclusion of scripts.

@masives
Copy link
Author

masives commented Sep 19, 2018

I'm using dynamic imports as we're currently supporting 7 languages with more in sight. Adding it in every place in code is tiresome (and prone to errors) as we might overlook adding it some place. Since our available languages are stored in config (which both app and webpack.config can access) it's the most convenient solution.

The reason I'm putting it here is that it's a quite common use case to have moment.js using locales with context replacement plugin (dynamically loading locales and excluding unused)

As for your last comment - you're correct it's not a tree shaking, but this term is often applied to this operation. If I'm not mistaken webpack uses term tree shaking while it only bundles files that are accesible (script inclusion).

@andrew-yangy
Copy link
Member

andrew-yangy commented Sep 19, 2018

Tree shaking and lazy loading are different terms. Tree shaking is to exclude the unused files or scripts, I think what you are trying here is webpack code splitting, which can be done by dynamic import(from wepack v2). It will generate a separate chunk file which can be requested lazily, it's a common use case for i18n.
https://webpack.js.org/guides/code-splitting/#dynamic-imports

@stevemao
Copy link
Member

#12 is already talking about this. See https://github.com/jmblog/how-to-optimize-momentjs-with-webpack

@masives
Copy link
Author

masives commented Sep 20, 2018

@ddvkid yes, there are dynamic imports you are correct. If your webpack config isn't setup to create separate chunks these will get to main bundle. However, I believe it's not a good practice to generate a lot of chunks that will be unused - this will unnecessary prolong build process.

Once again - the reason I suggested to include this case is because for long time I was hesitating to move from moment.js to date-fns since I wasn't sure if I can load only languages I need without the need to specifically define this in each place of use. There was no documentation on that (apart from, "do it yourself and include everything by hand") which is why I want to save that pain to others. If you feel like it doesn't fit here you can just close the issue.

@stevemao
Copy link
Member

Once again - the reason I suggested to include this case is because for long time I was hesitating to move from moment.js to date-fns since I wasn't sure if I can load only languages I need without the need to specifically define this in each place of use. There was no documentation on that (apart from, "do it yourself and include everything by hand") which is why I want to save that pain to others.

This feels like a webpack config tip which has nothing to do with moment.js or date-fns...

I'm not sure what you want to add to the docs but if you submit a PR we can have a look!

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

3 participants