Wie kann verhindert werden, dass moment.js Gebietsschemas mit Webpack lädt?

199

Gibt es eine Möglichkeit, das moment.jsLaden aller Gebietsschemas (ich brauche nur Englisch) zu stoppen, wenn Sie Webpack verwenden? Ich schaue auf die Quelle und es scheint, dass wenn hasModuledefiniert ist, was es für Webpack ist, dann versucht es immer zu require()jedem Gebietsschema. Ich bin mir ziemlich sicher, dass dies eine Pull-Anfrage erfordert, um das Problem zu beheben. Aber gibt es eine Möglichkeit, dies mit der Webpack-Konfiguration zu beheben?

Hier ist meine Webpack-Konfiguration zum Laden von momentjs:

resolve: {
            alias: {
                moment: path.join(__dirname, "src/lib/bower/moment/moment.js")
            },
        },

Dann mache ich es einfach, wo immer ich es brauche require('moment'). Dies funktioniert, fügt meinem Bundle jedoch etwa 250 KB nicht benötigte Sprachdateien hinzu. Außerdem benutze ich die Bower-Version von momentjs und gulp.

Auch wenn dies nicht durch die Webpack-Konfiguration behoben werden kann, finden Sie hier einen Link zu der Funktion, in der die Gebietsschemas geladen werden . Ich habe versucht && module.exports.loadLocales, die ifAussage zu ergänzen, aber ich denke, Webpack funktioniert nicht so, wie es funktionieren würde. Es ist einfach requireegal was. Ich denke, es wird jetzt eine Regex verwendet, daher weiß ich nicht wirklich, wie Sie es überhaupt reparieren würden.

epelc
quelle
Haben Sie versucht, Moment via nmpanstelle von zu verwenden bower?
Andreas Köberle
Ich verwende bower für alle meine Client-Bibliotheken und npm für alle meine Build-Tools. Ich möchte es so halten, weil meine Projekte so angelegt sind. Auch wenn Sie sich die letzte Antwort von github.com/moment/moment/issues/1866 ansehen, habe ich mein eigenes Problem gelöst, aber es erfordert eine geringfügige Änderung der Quelle. Ich weiß immer noch nicht, wie ich das richtig beheben soll, da ich nicht weiß, wie Sie zwischen Knoten und Webpack unterscheiden würden.
Epelc

Antworten:

304

Der Code require('./locale/' + name)kann jede Datei im localeVerzeichnis verwenden. Das Webpack enthält also jede Datei als Modul in Ihrem Bundle. Es kann nicht wissen, welche Sprache Sie verwenden.

Es gibt zwei Plugins , die nützlich sind, um dem Webpack mehr Informationen darüber zu geben, welches Modul in Ihrem Bundle enthalten sein soll: ContextReplacementPluginund IgnorePlugin.

require('./locale/' + name)wird als Kontext bezeichnet (eine Anforderung, die einen Ausdruck enthält). Das Webpack leitet einige Informationen aus diesem Codefragment ab: Ein Verzeichnis und ein regulärer Ausdruck. Hier : directory = ".../moment/locale" regular expression = /^.*$/. Standardmäßig ist also jede Datei im localeVerzeichnis enthalten.

Das ContextReplacementPluginermöglicht die gefolgert Informationen dh bietet einen neuen regulären Ausdruck außer Kraft zu setzen (wählen Sie die gewünschten Sprachen enthalten).

Ein anderer Ansatz besteht darin, die Anforderung mit dem zu ignorieren IgnorePlugin.

Hier ist ein Beispiel:

var webpack = require("webpack");
module.exports = {
  // ...
  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|fr|hu/)
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
};
Tobias K.
quelle
3
Können Sie erklären, wie Sie den Ignorier-Loader verwenden? Ich habe "new webpackreg.IgnorePlugin (/\.\/ locale \ /.+. Js $ /, [])" ausprobiert, aber das hat nicht funktioniert. Auch das contextReplacementPlugin hat die Dateien immer noch in mein Bundle aufgenommen. Ich denke nur, dass sie nicht verwendet wurden.
Epelc
9
Sie können sich dieses Problem ansehen ( github.com/webpack/webpack/issues/198 ), das eine ausführliche Diskussion über moment + webpack enthält.
Tobias K.
2
Vielen Dank, ich denke new webpack.IgnorePlugin(/^\.\/lang$/, /moment$/)von Ihrem Kommentar zu Github wird funktionieren.
Epelc
16
In den Webpack-Dokumenten ist das zweite Argument ein Array von regulären Ausdrücken. Ich habe versucht, plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]) ],was gut funktioniert hat.
Alex K
6
@AlexKinnee Die Klammer-Notation in den Dokumenten bedeutet, dass es sich um ein optionales Argument handelt, nicht um ein Array.
Yangmillstheory
8

In unser Projekt schließe ich einen Moment wie diesen ein: import moment from 'moment/src/moment';und das scheint den Trick zu tun. Unsere Verwendung von Momenten ist jedoch sehr einfach, daher bin ich mir nicht sicher, ob es Inkonsistenzen mit dem SDK geben wird. Ich denke, dies funktioniert, weil WebPack nicht weiß, wie die Gebietsschemadateien statisch zu finden sind, sodass Sie eine Warnung erhalten (die durch Hinzufügen eines leeren Ordners unter leicht ausgeblendet werden kann moment/src/lib/locale/locale), aber kein Gebietsschema enthält.

Adam McCormick
quelle
1
Ich bin mir nicht sicher, wie dieser für euch funktioniert ... Ich habe gerade versucht, gegen diesen github.com/angular/angular-cli/issues/6137 zu kämpfen, und habe dann einfach github.com/ksloan/moment-mini verwendet . Die richtige modulare momentBibliothek wird irgendwann mit Version 3 github.com/moment/moment/milestone/15 aufwarten .
kuncevic.dev
3

Die richtige modulare momentBibliothek wird irgendwann mit Version 3 verfügbar sein, so dass --ejectich derzeit Angular-Cli verwende, ohne dass ich gerade https://github.com/ksloan/moment-mini like verwendet habeimport * as moment from 'moment-mini';

kuncevic.dev
quelle
2

Basierend auf der Antwort von Adam McCrmick waren Sie nah dran. Ändern Sie Ihren Alias ​​in:

resolve: {
    alias: {
        moment: 'moment/src/moment'
    },
},
Bigopon
quelle
1
Nur ein Wort der Warnung, dass dies das Verhalten aller von Ihnen enthaltenen Module ändert und interessante Probleme mit Bibliotheken von Drittanbietern verursachen kann. Es sollte aber im Allgemeinen funktionieren
Adam McCormick
1
Können Sie das näher erläutern? Ich bin nicht mit allen Alias-Anwendungsfällen vertraut. Nach meinem Verständnis wäre es nur wichtig, wenn Sie dieses Modul berühren würden, in diesem Fall "Moment"
Bigopon
3
Wenn Sie Auflösungsaliasnamen festlegen, gelten diese für jede Verwendung von Import oder Anforderungen in Ihrem System (einschließlich Bibliotheken, von denen Sie abhängig sind). Wenn Sie also von einem Modul abhängig sind, ändern Sie das Ergebnis auch für dieses Modul. Dies tritt auf, wenn Sie einen Alias ​​festlegen, der mit einem Knotenmodul in Ihrem Abhängigkeitsbaum in Konflikt steht (z. B. "Ereignisse", wenn Ihre Abhängigkeiten diese Bibliothek verwenden). In der Praxis hatte ich nur ein Problem mit Namenskonflikten, nicht mit solchen Verhaltensverfeinerungen, aber dies ist ein gefährlicherer Ansatz als das Ändern einer Importanweisung.
Adam McCormick
2

Mit webpack2und aktuellen Versionen von moment können Sie Folgendes tun:

import {fn as moment} from 'moment'

Und dann in webpack.config.jsdir:

resolve: {
    packageMains: ['jsnext:main', 'main']
}
Kevin
quelle
1
Ich denke du meinstmainFields: ...
Guillermo Grau
Schauen Sie sich webpack2 an und stellen Sie sicher, dass sich der Feldname geändert hat.
Kevin