如何防止 moment.js 使用 webpack 加载语言环境?

Posted

技术标签:

【中文标题】如何防止 moment.js 使用 webpack 加载语言环境?【英文标题】:How to prevent moment.js from loading locales with webpack? 【发布时间】:2014-10-12 14:37:24 【问题描述】:

当您使用 webpack 时,有什么方法可以阻止 moment.js 加载所有语言环境(我只需要英语)?我正在查看源代码,似乎如果为 webpack 定义了 hasModule,那么它总是尝试在每个语言环境中使用 require()。我很确定这需要一个拉取请求来修复。但是有什么办法可以通过 webpack 配置解决这个问题?

这是我加载 momentjs 的 webpack 配置:

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

然后在任何我需要它的地方,我只需要require('moment')。这可行,但它在我的包中添加了大约 250 kB 的不需要的语言文件。另外我正在使用momentjs和gulp的凉亭版本。

另外,如果 webpack 配置无法解决这个问题,这里是 a link to the function where it loads the locales。我尝试将&& module.exports.loadLocales 添加到if 语句中,但我猜webpack 实际上并不能以这样的方式工作。无论如何,它只是requires。我认为它现在使用正则表达式,所以我真的不知道你会如何修复它。

【问题讨论】:

您是否尝试过使用时刻通过nmp 而不是bower 我的所有客户端库都使用 bower,所有构建工具都使用 npm。我想保持这种方式,因为我的项目是如何布局的。另外,如果您查看github.com/moment/moment/issues/1866 的最后回复,我解决了我自己的问题,但它需要对源代码进行少量编辑。我仍然不知道如何以正确的方式解决这个问题,因为我不知道如何区分 node 和 webpack。 【参考方案1】:

代码require('./locale/' + name) 可以使用locale 目录中的每个文件。所以 webpack 将每个文件作为模块包含在你的包中。它无法知道您使用的是哪种语言。

two plugins 有助于为 webpack 提供有关应将哪个模块包含在您的包中的更多信息:ContextReplacementPluginIgnorePlugin

require('./locale/' + name) 称为context(包含表达式的要求)。 webpack 从这段代码中推断出一些信息:一个目录和一个正则表达式。在这里:directory = ".../moment/locale"regular expression = /^.*$/。所以默认情况下,locale 目录中的每个文件都包含在内。

ContextReplacementPlugin 允许覆盖推断的信息,即提供新的正则表达式(以选择要包含的语言)。

另一种方法是使用 IgnorePlugin 忽略要求。

这是一个例子:

var webpack = require("webpack");
module.exports = 
  // ...
  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|fr|hu/)
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
;

【讨论】:

你能解释一下如何使用忽略加载器吗?我尝试了`new webpackreg.IgnorePlugin(/\.\/locale\/.+.js$/, [])`,但没有奏效。此外,contextReplacementPlugin 仍然包含我的包中的文件,我只是认为它没有使用它们。 你可以看看这个 issue (github.com/webpack/webpack/issues/198),里面有关于 moment+webpack 的详细讨论。 谢谢您,我认为您在 github 上的评论中的new webpack.IgnorePlugin(/^\.\/lang$/, /moment$/) 会起作用。 在 webpack 文档中,第二个参数是一个正则表达式数组。我试过plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]) ],,效果很好。 @AlexKinnee 括号符号in the docs 表示它是可选参数,而不是数组。【参考方案2】:

在我们的项目中,我包含这样的时刻:import moment from 'moment/src/moment';,这似乎可以解决问题。不过,我们对 moment 的使用非常简单,所以我不确定是否会与 SDK 有任何不一致。我认为这是可行的,因为 WebPack 不知道如何静态查找语言环境文件,因此您会收到警告(通过在 moment/src/lib/locale/locale 添加一个空文件夹很容易隐藏)但不包括语言环境。

【讨论】:

不知道这对你有什么作用......我只是试图对抗github.com/angular/angular-cli/issues/6137,然后最终使用github.com/ksloan/moment-mini。适当的模块化 moment 库将在某个时候提供版本 3 github.com/moment/moment/milestone/15。【参考方案3】:

更新:2021 年 您可能还想签出许多其他库:

https://date-fns.org https://github.com/iamkun/dayjs

原始答案: 似乎是正确的模块化 moment 库 will never come up 但是,我刚刚结束了使用 https://github.com/ksloan/moment-mini 之类的 import * as moment from 'moment-mini';

【讨论】:

【参考方案4】:

根据 Adam McCrmick 的回答,您很接近,请将您的别名更改为:

resolve: 
    alias: 
        moment: 'moment/src/moment'
    ,
,

【讨论】:

请注意,这将改变您包含的所有模块的行为,并可能导致第三方库出现有趣的问题。它应该可以正常工作 你能详细说明一下吗?我对所有别名用例都没有经验。据我了解,只有你触摸了那个模块才重要,在这种情况下是“时刻” 当您设置解析别名时,它们适用于您系统中的任何 import 或 require 用法(包括您依赖的库)。因此,如果您依赖于所需时刻的模块,您也将更改该模块的结果。如果您碰巧设置了与依赖关系树中的节点模块冲突的别名(例如“事件”,例如,如果您的依赖关系使用该库),则会出现这种情况。在实践中,我只遇到过名称冲突问题,而不是像这样的行为改进问题,但这是一种比更改一个导入语句更危险的方法。【参考方案5】:

使用 webpack2 和最新版本的 moment,您可以:

import fn as moment from 'moment'

然后在webpack.config.js 你这样做:

resolve: 
    packageMains: ['jsnext:main', 'main']

【讨论】:

我猜你的意思是mainFields: ... 看看webpack2,很确定字段名变了。【参考方案6】:

这是在 NPM 安装程序中使用 postinstall script 的另一个解决方案。

您可以在 package.json 文件中添加一行:


  "scripts": 
    ...
    "postinstall": "find node_modules/moment/locale -type f -not -name 'en-gb.js' -not -name 'pl.js' -printf '%p\\n' | xargs rm"
    ...
  

npm install 完成安装包后,不需要的语言环境将立即被删除。

在我的情况下,只有 en-gbpl 语言环境将保留在捆绑包中。

如果您已经有postinstall 脚本,您可以将脚本添加到现有命令中:


  "scripts": 
    ...
    "postinstall": "previous_command && find node_modules/moment/locale -type f -not -name 'en-gb.js' -not -name 'pl.js' -printf '%p\\n' | xargs rm"
    ...
  

【讨论】:

以上是关于如何防止 moment.js 使用 webpack 加载语言环境?的主要内容,如果未能解决你的问题,请参考以下文章

react 在creact-react-app中屏蔽console.log、解决moment.js体积过大

如何在javascript中使用moment(moment.js)做大于或等于?

如何使用moment-timezone.js获取客户端时区

使用moment.js解析时如何忽略时区

如何使用 Moment.js 返回当前时间戳?

如何在 moment.js 持续时间内使用 format()?