Como impedir o moment.js de carregar localidades com o webpack?

199

Existe alguma maneira de você parar moment.jsde carregar todos os locais (só preciso de inglês) quando você estiver usando o webpack? Eu estou olhando a fonte e parece que, se hasModulefor definido, o que é para o webpack, ele sempre tenta require()todos os códigos de idioma. Tenho certeza de que isso precisa de uma solicitação pull para corrigir. Mas existe alguma maneira de corrigir isso com a configuração do webpack?

Aqui está minha configuração do webpack para carregar momentjs:

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

Então, em qualquer lugar que eu precisar, eu apenas preciso require('moment'). Isso funciona, mas está adicionando cerca de 250 kB de arquivos de idioma desnecessários ao meu pacote. Também estou usando a versão bower do momentjs e gulp.

Além disso, se isso não puder ser corrigido pela configuração do webpack, há um link para a função em que ele carrega os códigos de idioma . Tentei adicionar && module.exports.loadLocalesà ifdeclaração, mas acho que o webpack não funciona de uma maneira que funcionaria. Apenas requirenão importa o quê. Eu acho que ele usa um regex agora, então eu realmente não sei como você iria corrigi-lo.

epelc
fonte
Você já tentou usar o momento via em nmpvez de bower?
Andreas Köberle
Estou usando o bower para todas as minhas bibliotecas de clientes e o npm para todas as minhas ferramentas de construção. Eu quero mantê-lo assim por causa de como meus projetos são apresentados. Além disso, se você olhar para a última resposta de github.com/moment/moment/issues/1866 , resolvi meu próprio problema, mas isso requer uma edição menor da fonte. Ainda não sei como corrigir isso da maneira certa, pois não sei como você distinguiria entre nó e webpack.
epelc 20/08/14

Respostas:

305

O código require('./locale/' + name)pode usar todos os arquivos no localediretório Portanto, o webpack inclui todos os arquivos como módulo em seu pacote. Ele não pode saber qual idioma você está usando.

Existem dois plug-ins que são úteis para fornecer ao webpack mais informações sobre qual módulo deve ser incluído no seu pacote: ContextReplacementPlugine IgnorePlugin.

require('./locale/' + name)é chamado de contexto (um requisito que contém uma expressão). O webpack infere algumas informações deste fragmento de código: Um diretório e uma expressão regular. Aqui: directory = ".../moment/locale" regular expression = /^.*$/. Portanto, por padrão, todos os arquivos no localediretório estão incluídos.

O ContextReplacementPluginpermite substituir as informações inferidas, ou seja, fornecer uma nova expressão regular (para escolher os idiomas que você deseja incluir).

Outra abordagem é ignorar o requisito com o IgnorePlugin.

Aqui está um exemplo:

var webpack = require("webpack");
module.exports = {
  // ...
  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|fr|hu/)
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
};
Tobias K.
fonte
3
Você pode explicar como usar o carregador de ignorar? Tentei o `novo webpackreg.IgnorePlugin (/\.\/ locale \ /.+. Js $ /, [])` mas isso não funcionou. Além disso, o contextReplacementPlugin ainda incluía os arquivos no meu pacote, acho que não os estava usando.
epelc 23/08/14
9
Você pode dar uma olhada nesta edição ( github.com/webpack/webpack/issues/198 ), que contém uma discussão detalhada sobre o momento + webpack.
Tobias K.
2
Obrigado, acho que new webpack.IgnorePlugin(/^\.\/lang$/, /moment$/)com o seu comentário no github funcionará.
epelc
16
Nos documentos do webpack, o segundo argumento é uma matriz de regexes. Eu tentei o plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]) ],que funcionou muito bem.
Alex K
6
@AlexKinnee A notação de colchete nos documentos significa que é um argumento opcional, não uma matriz.
yangmillstheory
8

Em nosso projeto, incluo momentos como este: import moment from 'moment/src/moment';e isso parece funcionar. Nosso uso do momento é muito simples, portanto, não tenho certeza se haverá alguma inconsistência com o SDK. Eu acho que isso funciona porque o WebPack não sabe como encontrar os arquivos de localidade estaticamente, então você recebe um aviso (é fácil ocultar adicionando uma pasta vazia em moment/src/lib/locale/locale), mas nenhum local inclui.

Adam McCormick
fonte
1
Não tenho certeza pessoal, como este está funcionando para você ... Tentei combater esse github.com/angular/angular-cli/issues/6137 e acabei usando github.com/ksloan/moment-mini . A momentbiblioteca modular adequada apresentará a versão 3 github.com/moment/moment/milestone/15 em algum momento.
Kuncevic.dev
2

Com base na resposta de Adam McCrmick, você estava perto, altere seu alias para:

resolve: {
    alias: {
        moment: 'moment/src/moment'
    },
},
bigopon
fonte
1
Apenas uma palavra de aviso, que isso mudará o comportamento de todos os módulos incluídos e poderá causar problemas interessantes nas bibliotecas de terceiros. Deve funcionar em geral embora
Adam McCormick
1
Você pode elaborar ? Não tenho experiência com todos os casos de uso de alias. No meu entendimento, seria apenas uma questão se você tocou nesse módulo, neste caso 'momento'
bigopon
3
Quando você define aliases de resolução, eles se aplicam a qualquer uso de importação ou exigência em seu sistema (incluindo bibliotecas das quais você depende). Portanto, se um módulo do qual você depende no momento necessário, você também alteraria o resultado desse módulo. Isso acontece se você definir um alias que entre em conflito com um módulo de nó na sua árvore de dependências (como "eventos", por exemplo, se suas dependências usarem essa biblioteca). Na prática, só tive um problema com conflitos de nome, não com refinamentos de comportamento como esse, mas essa é uma abordagem mais perigosa do que alterar uma declaração de importação.
Adam McCormick
2

Com webpack2e versões recentes do momento, você pode fazer:

import {fn as moment} from 'moment'

E então webpack.config.jsvocê faz:

resolve: {
    packageMains: ['jsnext:main', 'main']
}
Kevin
fonte
1
Eu acho que você quer dizermainFields: ...
Guillermo Grau
Veja o webpack2, com certeza o nome do campo alterado.
Kevin