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

How would you exclude moment.js locale in a proper way? #6137

Closed
kuncevic opened this issue May 1, 2017 · 38 comments
Closed

How would you exclude moment.js locale in a proper way? #6137

kuncevic opened this issue May 1, 2017 · 38 comments

Comments

@kuncevic
Copy link

kuncevic commented May 1, 2017

Bug Report or Feature Request

  • [x ] question

Versions.

@angular/cli: 1.0.1
node: 7.8.0
os: win32 x64

Details

I've got the whole locale ended up in my bundle:

image

As I am not using --eject flag this solution moment/moment#2416 (comment) in not working for me.

I discovered this SO answer which is kind of not really works for me, getting like Error: Can't resolve './locale' in runtime.

Is there any proper solution with angular-cli to exclude the moment locale without --eject?

@alexciesielski
Copy link

alexciesielski commented May 1, 2017

Just include the .min.js version which does not include any locales, and then include the locale you need.
This is what I've got:

"scripts": [
    "../node_modules/moment/min/moment.min.js",
    "../node_modules/moment/locale/pl.js",
]

Edit: Found out that my solution does not work, and in fact also includes all locales

@kuncevic
Copy link
Author

kuncevic commented May 1, 2017

@ciesielskico thanks for coming back so quick. As SO has already similar question but without the right answer for me so I just decided to ask here hoping to get the best help. Thanks a lot.

@kuncevic kuncevic closed this as completed May 1, 2017
@kuncevic
Copy link
Author

kuncevic commented May 1, 2017

@ciesielskico is your bundle looking good after all?

By importing through the "scripts": [] and then doing import * as moment from 'moment'; just got multiple moments in a bundles - one in the vendor bundle with all locales(same as I initially got), and another one in a scripts bundle.

P.S
Anyway it is sounds like there is too much hassle of using current moment until the proper modular version will be released https://github.com/moment/moment/milestone/15. So currently just ended up of using https://github.com/ksloan/moment-mini which is works fine for me:

import * as moment from 'moment-mini';

image

@kirillgroshkov
Copy link

just missing typings for moment-min. Will probably fork and add myself..

@alexciesielski
Copy link

alexciesielski commented Aug 10, 2017 via email

@kirillgroshkov
Copy link

Forked with typings, enjoy:

https://github.com/kirillgroshkov/moment-mini-ts

npm i moment-mini-ts

import * as moment from 'moment-mini-ts'

@Lakston
Copy link
Contributor

Lakston commented Nov 22, 2017

This looks very intersting !

How would you import specific locales this way ?

@jesulink2514
Copy link

It's quite difficult to get ride of moment when some packages (like material2) depend on it :(

@felipefialho
Copy link

Can I import some locale on moment-mini?

@petivagyok16
Copy link

@jesulink2514 Im facing with the same issue. Using material 2, but cannot use material-mini-ts due to dependency. Could you find any solution?

@Brandinga
Copy link

Brandinga commented Feb 20, 2018

@petivagyok16
we are using a npm script after install, found somewhere ...

`
var globby = require('globby');
var rimraf = require('rimraf');

globby(['./node_modules/moment/locale/*', '!./node_modules/moment/locale/de.js', '!./node_modules/moment/locale/de-at.js', '!./node_modules/moment/locale/de-ch.js'])
.then(function then(paths) {
paths.map(function map(item) {
rimraf.sync(item);
});
});
`

@TomDemulierChevret
Copy link

TomDemulierChevret commented May 9, 2018

There is a simplier solution if you want to exlude all locales, in src/tsconfig.app.json add this :

"compilerOptions": {
    "paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ]
    }
}

It will instruct the compiler to use the minified-without-locale bundle instead of building from the sources.

Why use this instead of moment-mini ?

  1. Well the moment-min repo is not always up to date with the official moment repo, therefore you can be stuck on an old version
  2. If you use other libraries that depend on moment (such as moment-timezone), by default it will bundle the full moment with locale into your app. The config above avoid this pitfall.

@MikeDabrowski
Copy link

@TomDemulierChevret
How Can I add just the locales I need ?

@naveedahmed1
Copy link

@TomDemulierChevret thanks for sharing this. But I am receiving below warning when I build my app:

WARNING in ./node_modules/moment/min/moment.min.js
Module not found: Error: Can't resolve './locale' in 'D:\MyProject\node_modules\moment\min'

@TomDemulierChevret
Copy link

@MikeDabrowski I'm not sure, but you should just need to import the locales you need (see https://momentjs.com/docs/#/i18n/loading-into-browser/).

@naveedahmed1 I have the same warning but haven't faced any issue yet. As long as you don't use functionnality from moment that requires locales, this shouldn't be an problem.

@maximpn
Copy link

maximpn commented Sep 6, 2018

I tried @angular-builders/custom-webpack with the @angular/cli 6.1 and it works properly. I'm able to add IngorePlugin and there is no warnings in the console.

@dreamdevil00
Copy link

@katzz0 ignore-plugin demo shows how to ignore all locale files, but how to preserve one, for example, 'fr'

@dreamdevil00
Copy link

I found a solution in momentjs issues, then I tried it with @angular-builders/custom-webpack.
This is my config:

./extra-webpack.config.js

'use strict';

const webpack = require('webpack');

// https://webpack.js.org/plugins/context-replacement-plugin/
module.exports = {
  plugins: [new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)]
};

and angular.json

...
 "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "./extra-webpack.config.js",
              "replaceDuplicatePlugins": true,
              "mergeStrategies": {
                "externals": "prepend"
              }
            },
...

It works fine. You can select whatever locale you want.

Hope this will help you.

@danieldiazastudillo
Copy link

@dreamdevil00 Nice. One question that i can't figure out. The webpack devDependency must be aligned with the one used by Angular CLI or did you just used @latest for that?

@dreamdevil00
Copy link

@danieldiazastudillo Just require webpack, needn't to install webpack as devdependency again.

@DavidDon13
Copy link

I tried @angular-builders/custom-webpack with the @angular/cli 6.1 and it works properly. I'm able to add IngorePlugin and there is no warnings in the console.

how did you ignorePlugin warning? I'm using angular6 and haven't been able to suppress the ./locale warning

@dreamdevil00
Copy link

@DavidDon13 Please use this solution solution

@FrogMonkeyBird
Copy link

FrogMonkeyBird commented Oct 26, 2018

For anyone else with this redundant-moment-weight-problem, I highly recommend using DayJS:
https://github.com/iamkun/dayjs
It has mostly the same functionality, but with at more modular approach, where you import the basic package (6 KB) and only what you need in chuncks after that.

I'm just gonna leave this here, in case anyone needs more persuasion:
moment-to-dayjs

@felipefialho
Copy link

@FrogMonkeyBird DayJS provide integration with Angular Material?

@FrogMonkeyBird
Copy link

@FrogMonkeyBird DayJS provide integration with Angular Material?

I have no idea, sorry - Not an expert in DayJS :)

@CAspeling
Copy link

CAspeling commented Nov 2, 2018

There is a simplier solution if you want to exlude all locales, in src/tsconfig.app.json add this :

"compilerOptions": {
    "paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ]
    }
}

@Brandinga
Could I adjust this to also pull in just the single locale I want? I would love to find out how to make this work but am too new to tsconfig and angular cli to make the warning go away. Something like this?

"paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
        ,"../node_modules/moment/locale/en-au.js"
      ]
    }

@rynop
Copy link

rynop commented Nov 20, 2018

For those of you who use moment-timezone there is a trick to reduce the size (if you can get away with 2012-2022 dates):

import * as moment from 'moment-timezone/builds/moment-timezone-with-data-2012-2022.min';

Note that you don't have to include moment separate from this. moment-timezone includes the moment implementation.

I wrote a blog post that ties all this stuff together, and also includes moment timezone.

@ktsangop
Copy link

ktsangop commented Jun 6, 2019

There is a simplier solution if you want to exlude all locales, in src/tsconfig.app.json add this :

"compilerOptions": {
    "paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ]
    }
}

It will instruct the compiler to use the minified-without-locale bundle instead of building from the sources.

Why use this instead of moment-mini ?

  1. Well the moment-min repo is not always up to date with the official moment repo, therefore you can be stuck on an old version
  2. If you use other libraries that depend on moment (such as moment-timezone), by default it will bundle the full moment with locale into your app. The config above avoid this pitfall.

I have tried the solution above. I'm using moment-timezone, and see no difference in the bundle size. All locales are still bundled.

Sorry, but i'm confused, is this supposed to work with moment-timezone also or is it a fix only for projects that use the moment-js package.

Thanks in advance!

@TomDemulierChevret
Copy link

TomDemulierChevret commented Jun 6, 2019

@ktsangop This is working with moment-timezone.

In one of my current projet I have this config :

"compilerOptions": {
    "paths": {
      "plotly.js": [
        "../node_modules/plotly.js/dist/plotly-basic.min.js"
      ],
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ],
      "moment-timezone": [
        "../node_modules/moment-timezone/builds/moment-timezone-with-data-2012-2022.min.js"
      ]
    }
}

Wich leads to these sizes once gziped :

  • moment => 16,67 KB
  • moment-timezone => 9,03 KB
  • plotly => 265,63 KB

Without the above config, I get :

  • moment => 71,76 KB
  • moment-timezone => 35,51 KB
  • plotly => 909,27 KB

As you can see, the difference is quite substantial. 😄

Sidenote

Plotly is one of the best (if not the best) chart library available : MIT license + nearly every possible chart type + reaaaaally deep customisation
But like every chart library it's bloated as f***.

If you want to use it (or any chart library), you should definitly include it in a lazy-loaded module and not in your root module.

@ktsangop
Copy link

ktsangop commented Jun 6, 2019

@TomDemulierChevret Thank you so much for the response.
Unfortunately, still no difference in the bundle size...
btw, i use :

"moment-timezone": "0.5.21",
"@angular/core": "7.2.15",
"@angular/cli": "7.1.4",
"@angular/compiler-cli": "7.2.15",
"typescript": "3.2.4"

I build the project using this :
ng build --prod --stats.json
And use webpack-bundle-analyzer to analyze bundle size

@TomDemulierChevret
Copy link

My dependencies are quite similar to yours :

"moment-timezone": "^0.5.23",
"@angular/core": "7.2.8",
"@angular/cli": "^7.3.5",
"@angular/compiler-cli": "7.2.8",
"typescript": "3.2.4"

I also use webpack-bundle-analyzer (3.0.3) for the bundle.

There must be something wrong with your tsconfig.app.json file.
Can you post it entirely ?

@ktsangop
Copy link

ktsangop commented Jun 6, 2019

BTW, i cannot apply the moment-timezone-with-data-2012-2022.min.js workaround, so i would like to remove just moment locale.

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ]
    },
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

@ktsangop
Copy link

ktsangop commented Jun 12, 2019

Seems like i had another (internal) lib that was also dependent on moment...
I've managed to remove locales, from the other lib also, using the same config.
Now my bundles are finally smaller, thank you!
:)

@madmurl0c
Copy link

I managed to get moment.min.js loading but what is the best practice to lazy load the language that I want to use? I use Angular's i18n feature with one configuration per language (currently 'de' and 'en') which results in two apps (one for each language). I tried using the script: [] tag in the configurations to load the required language but that didn't work out.
Does someone know a fix?

@khazaddoom
Copy link

There is a simplier solution if you want to exlude all locales, in src/tsconfig.app.json add this :

"compilerOptions": {
    "paths": {
      "moment": [
        "../node_modules/moment/min/moment.min.js"
      ]
    }
}

It will instruct the compiler to use the minified-without-locale bundle instead of building from the sources.
Why use this instead of moment-mini ?

  1. Well the moment-min repo is not always up to date with the official moment repo, therefore you can be stuck on an old version
  2. If you use other libraries that depend on moment (such as moment-timezone), by default it will bundle the full moment with locale into your app. The config above avoid this pitfall.

I have tried the solution above. I'm using moment-timezone, and see no difference in the bundle size. All locales are still bundled.

Sorry, but i'm confused, is this supposed to work with moment-timezone also or is it a fix only for projects that use the moment-js package.

Thanks in advance!

Yes i too experienced same! Trying other approaches now...

@keserwan
Copy link

keserwan commented Aug 2, 2019

I did the dirty way :)
I tried all the above solutions with no luck.

I simply deleted the unwanted locales from "\node_modules\moment\locale", and everything went well in production.

1st, I created tools/delete-moment-locale.js:

var fs = require('fs');
rmDir = function(dirPath) {
try { var files = fs.readdirSync(dirPath); }
catch(e) { console.log(e); return; }
if (files.length > 0)
for (var i = 0; i < files.length; i++) {
var filePath = dirPath + '/' + files[i];

    if (files[i] === 'ar.js' || files[i] === 'en-gb.js'){continue;}//exclude required locales

    if (fs.statSync(filePath).isFile())
      fs.unlinkSync(filePath);
    else
      rmDir(filePath);
  }
//fs.rmdirSync(dirPath);

};
rmDir("node_modules/moment/locale");

2nd) I called this code before my npm run build code in package.json:

"build:ssr": "node tools/delete-moment-locale.js && ...

@CAspeling
Copy link

@keserwan this is the kind of tool they need to make that strips all except locales specified.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests