Bagaimana mencegah moment.js dari memuat lokal dengan webpack?

199

Apakah ada cara Anda bisa berhenti moment.jsmemuat semua lokal (saya hanya perlu bahasa Inggris) ketika Anda menggunakan webpack? Saya melihat sumbernya dan tampaknya jika hasModuledidefinisikan, yang untuk webpack, maka ia selalu mencoba ke require()setiap lokal. Saya cukup yakin ini membutuhkan permintaan tarik untuk memperbaikinya. Tetapi apakah ada cara kita dapat memperbaikinya dengan konfigurasi webpack?

Ini konfigurasi webpack saya untuk memuat momentjs:

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

Lalu di mana pun saya membutuhkannya, saya lakukan saja require('moment'). Ini berfungsi tetapi ia menambahkan sekitar 250 kB file bahasa yang tidak dibutuhkan ke bundel saya. Saya juga menggunakan versi bower dari momentjs dan tegukan.

Juga jika ini tidak dapat diperbaiki oleh konfigurasi webpack di sini adalah tautan ke fungsi tempat memuat lokal . Saya mencoba menambahkan && module.exports.loadLocaleske ifpernyataan tapi saya kira Webpack tidak benar-benar bekerja dengan cara di mana yang akan bekerja. Tidak requirepeduli apa. Saya pikir itu menggunakan regex sekarang jadi saya tidak benar-benar tahu bagaimana Anda akan memperbaikinya.

Epelc
sumber
Sudahkah Anda mencoba menggunakan momen melalui nmpalih-alih bower?
Andreas Köberle
Saya menggunakan bower untuk semua lib klien saya, dan npm untuk semua alat build saya. Saya ingin tetap seperti ini karena bagaimana proyek saya ditata. Juga jika Anda melihat balasan terakhir dari github.com/moment/moment/issues/1866 saya memecahkan masalah saya sendiri tetapi membutuhkan edit sumber kecil. Saya masih tidak tahu bagaimana cara memperbaikinya dengan cara yang benar karena saya tidak tahu bagaimana Anda akan membedakan antara node dan webpack.
epelc

Jawaban:

305

Kode require('./locale/' + name)dapat menggunakan setiap file dalam localedirektori. Jadi webpack menyertakan setiap file sebagai modul dalam bundel Anda. Tidak dapat mengetahui bahasa yang Anda gunakan.

Ada dua plugin yang berguna untuk memberi webpack lebih banyak informasi tentang modul mana yang harus dimasukkan dalam bundel Anda: ContextReplacementPlugindan IgnorePlugin.

require('./locale/' + name)disebut konteks (persyaratan yang berisi ekspresi). webpack menyimpulkan beberapa informasi dari fragmen kode ini: Direktori dan ekspresi reguler. Di sini: directory = ".../moment/locale" regular expression = /^.*$/. Jadi secara default setiap file dalam localedirektori disertakan.

The ContextReplacementPluginmemungkinkan untuk menimpa informasi disimpulkan yaitu memberikan ekspresi reguler baru (untuk memilih bahasa yang ingin Anda sertakan).

Pendekatan lain adalah mengabaikan kebutuhan dengan IgnorePlugin.

Berikut ini sebuah contoh:

var webpack = require("webpack");
module.exports = {
  // ...
  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|fr|hu/)
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
};
Tobias K.
sumber
3
Bisakah Anda menjelaskan cara menggunakan loader yang diabaikan? Saya mencoba `webpackreg.IgnorePlugin baru (/ \. \ / lokal \ /.+. Js $ /, [])` tetapi itu tidak berhasil. Juga contextReplacementPlugin masih menyertakan file dalam bundel saya, saya hanya berpikir itu tidak menggunakannya.
epelc
9
Anda dapat melihat masalah ini ( github.com/webpack/webpack/issues/198 ) yang berisi diskusi terperinci tentang momen + webpack.
Tobias K.
2
Terima kasih, saya pikir new webpack.IgnorePlugin(/^\.\/lang$/, /moment$/)dari komentar Anda pada github akan berhasil.
epelc
16
Dalam dokumen webpack, argumen kedua adalah array dari regex. Saya mencoba plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]) ],yang bekerja dengan baik.
Alex K
6
@AlexKinnee Notasi braket dalam dokumen berarti ini argumen opsional, bukan array.
yangmillstheory
8

Dalam proyek kami, saya sertakan momen seperti ini: import moment from 'moment/src/moment';dan itu sepertinya berhasil. Penggunaan momen kami sangat sederhana, jadi saya tidak yakin apakah akan ada inkonsistensi dengan SDK. Saya pikir ini berfungsi karena WebPack tidak tahu bagaimana menemukan file lokal secara statis, sehingga Anda mendapatkan peringatan (mudah disembunyikan dengan menambahkan folder kosong di moment/src/lib/locale/locale) tetapi tidak ada lokal yang menyertakan.

Adam McCormick
sumber
1
Tidak yakin orang-orang bagaimana ini bekerja untuk Anda ... Saya baru saja mencoba melawan github.com/angular/angular-cli/issues/6137 dan kemudian berakhir dengan menggunakan github.com/ksloan/moment-mini . momentPustaka modular yang tepat akan hadir dengan Versi 3 github.com/moment/moment/milestone/15 di beberapa titik.
kuncevic.dev
3

momentPustaka modular yang tepat akan muncul dengan Versi 3 di beberapa titik jadi saat ini karena saya menggunakan angular-cli tanpa --ejectsaya baru saja menggunakan https://github.com/ksloan/moment-mini sepertiimport * as moment from 'moment-mini';

kuncevic.dev
sumber
2

Berdasarkan jawaban Adam McCrmick, Anda sudah dekat, ubah alias Anda menjadi:

resolve: {
    alias: {
        moment: 'moment/src/moment'
    },
},
bigopon
sumber
1
Hanya kata peringatan, bahwa ini akan mengubah perilaku untuk semua modul yang Anda sertakan dan dapat menyebabkan masalah menarik dengan perpustakaan pihak ketiga. Ini seharusnya bekerja secara umum
Adam McCormick
1
Bisakah Anda menguraikan? Saya tidak berpengalaman dengan semua kasus penggunaan alias. Dalam pemahaman saya, itu hanya masalah jika Anda menyentuh modul itu, dalam hal ini 'momen'
bigopon
3
Ketika Anda menetapkan alias penyelesaian, alias itu berlaku untuk setiap penggunaan impor atau persyaratan dalam sistem Anda (termasuk perpustakaan tempat Anda bergantung). Jadi, jika modul yang Anda andalkan bergantung pada momen yang diperlukan, Anda juga akan mengubah hasilnya untuk modul itu. Ini muncul jika Anda menetapkan alias yang bertentangan dengan modul simpul di pohon dependensi Anda (seperti "peristiwa" misalnya jika dependensi Anda menggunakan perpustakaan itu). Dalam praktiknya, saya hanya memiliki masalah dengan konflik nama, bukan penyempurnaan perilaku seperti ini, tetapi ini adalah pendekatan yang lebih berbahaya daripada mengubah satu pernyataan impor.
Adam McCormick
2

Dengan webpack2dan versi terbaru dari momen yang dapat Anda lakukan:

import {fn as moment} from 'moment'

Dan kemudian dalam diri webpack.config.jsAnda lakukan:

resolve: {
    packageMains: ['jsnext:main', 'main']
}
Kevin
sumber
1
Saya kira maksud AndamainFields: ...
Guillermo Grau
Lihatlah webpack2, cukup yakin bahwa nama bidang berubah.
Kevin