Keeping moment.js out of my Angular build output

Viewed 497

I'm developing an Angular Spa (using Angular CLI) and I would like to have moment.js included in the page as an external script:

    <script src="/lib/moment.min.js"></script>

This, because I want to move the loading of only the relevant locales to the server side, and having moment.js out of the build is the first step.

So, I need to make the rest of the build to work using this import mechanism, ideally keeping Moment.js typings somewhat working. Something like:

declare const moment: moment.MomentType;
// or something like
interface Window {
  moment: moment.MomentType
}

This syntax (or any variation of it I can come up) keeps me getting errors along the lines of Cannot find namespace 'moment'.

I already tried to remove every import { moment } from 'moment'; around, I tried variations of declare const moment: any;, but they don't give me type safety, and I can't find a way to import moment.d.ts, either via tsconfig "files" property or in the project's tsconfig.app.json "include" property.

Is there a way to make this work?

Thanks!

2 Answers

It seems I found a solution, after all.

The solution is twofold:

  1. Insert in the page a script tag for moment, and a tag for the appropriate locale. I do this in my server-generated MVC view. The same two tags are included in the index.html page I use for Angular development with ng serve.
    This provides a moment object inside the global window.
    <script src="/assets/lib/moment/moment.min.js"></script>
    <script src="/assets/lib/moment/locale/it.js"></script>
  1. In Angular dev mode, I removed EVERY single import moment from 'moment'; and import * as moment from 'moment'; or variations of it.
    Instead, I use a local const moment = window['moment'];.
    This would not give me any type safety, but I can leverage the new import syntax of Typescript (here for a nice presentation and here for the reference) to access the type of the moment module:
// just importing the module for the type
// will not add the module to the build output
export const moment: typeof import('moment') = window['moment'];
type Moment = import('moment').Moment;
type LongDateFormatSpec = import('moment').LongDateFormatSpec;
type DurationInputObject = import('moment').DurationInputObject;
type Locale = import('moment').Locale;

And, voilĂ , we just shaved ~300 KB from the build and can still write type safe code.

you can create a separate build file for moment js like this

angular.json

"scripts": [
  {
    "inject": true,
    "bundleName": "moment-build",
    "input": "node_modules/moment/min/moment.min.js"
  }
]

inject :true this add a script element for moment-build.js in index.html

as example this build by import the moment directly in main component

angular-build-result

and this the build result when I create a separate build file moment-build.js

final-build-result

Related