打包具有依赖关系的Browser/Server CommonJS模块
Packaging-up Browser/Server CommonJS modules with dependancies
假设我正在用JavaScript编写一个模块,该模块可以在浏览器和服务器上使用(带Node)。让我们称之为模块。假设Module将受益于另一个名为Dependency的模块中的方法。这两个模块都被编写为可供浏览器和服务器使用,类似于CommonJS风格:
module.js
if (typeof module !== 'undefined' && module.exports)
module.exports = Module; /* server */
else
this.Module = Module; /* browser */
dependency.js
if (typeof module !== 'undefined' && module.exports)
module.exports = Dependancy; /* server */
else
this.Dependancy = Dependancy; /* browser */
显然,Dependency可以在浏览器中直接使用。但是,如果Module中包含var dependancy = require('dependency');
指令,则"维护"该模块将变得更加麻烦。
我知道我可以在模块中执行依赖性的全局检查,如下所示:
var dependancy = this.Dependancy || require('dependancy');
但这意味着我的模块对浏览器安装有两个附加要求:
- 用户必须在其文档中包含dependency.js文件作为
<script>
- 并且用户必须确保在module.js之前加载此脚本
添加这两个需求带来了像CommonJS这样易于使用的模块化框架的想法。
对我来说,另一个选择是在Module包中包含第二个编译后的脚本,并使用browserfy捆绑dependency.js
。然后,我指示在浏览器中使用该脚本的用户包含该脚本,而服务器端用户则使用package.json
中列出的未绑定的条目脚本。这比第一种方式更好,但它需要一个预编译过程,每次更改库时(例如,在上传到GitHub之前)我都必须运行该过程。
还有其他我没有想过的方法吗?
目前给出的两个答案都非常有用,帮助我找到了当前的解决方案。但是,根据我的评论,它们并不能完全满足我对可移植性和易用性的特殊要求(对于客户端和模块维护者来说)。
最后,我在browserfy命令行界面中发现了一个特定的标志,它可以捆绑模块并将它们公开为全局变量,并在RequireJS中使用(如果需要)。Browserify(和其他人)称之为通用模块定义(UMD)。这里有更多关于这方面的信息。
通过在browserfy命令中传递--standalone
标志,我可以轻松地为UMD设置模块。
所以。。。
这是模块的package.js
:
{
"name": "module",
"version": "0.0.1",
"description": "My module that requires another module (dependancy)",
"main": "index.js",
"scripts": {
"bundle": "browserify --standalone module index.js > module.js"
},
"author": "shennan",
"devDependencies": {
"dependancy": "*",
"browserify": "*"
}
}
因此,当在我的模块的根目录时,我可以在命令行中运行:
$ npm run-script bundle
它将依赖关系捆绑到一个文件中,并根据UMD方法公开它们。这意味着我可以通过三种不同的方式引导模块:
NodeJS
var Module = require('module');
/* use Module */
浏览器香草
<script src="module.js"></script>
<script>
var Module = module;
/* use Module */
</script>
带RequireJS的浏览器
<script src="require.js"></script>
<script>
requirejs(['module.js'], function (Module) {
/* use Module */
});
</script>
再次感谢大家的投入。所有的答案都是有效的,我鼓励每个人都尝试一下,因为不同的用例需要不同的解决方案。
当然,您可以使用双方都有依赖关系的相同模块。您只需要更好地指定它。这是我使用的方式:
(function (name, definition){
if (typeof define === 'function'){ // AMD
define(definition);
} else if (typeof module !== 'undefined' && module.exports) { // Node.js
module.exports = definition();
} else { // Browser
var theModule = definition(), global = this, old = global[name];
theModule.noConflict = function () {
global[name] = old;
return theModule;
};
global[name] = theModule;
}
})('Dependency', function () {
// return the module's API
return {
'key': 'value'
};
});
这只是一个非常基本的示例——您可以返回函数、实例化函数或执行任何您喜欢的操作。在我的情况下,我将返回一个对象。
现在假设这是Dependency
类。您的Module
类看起来应该基本相同,但它应该有一个对Dependency
的依赖,比如:
function (require, exports, module) {
var dependency = require('Dependency');
}
在RequireJS中,这被称为Simplified CommonJS Wrapper:http://requirejs.org/docs/api.html#cjsmodule
因为在代码的开头有一个require
语句,它将被匹配为依赖项,因此它将被延迟加载,或者如果您在早期对其进行优化,则将其标记为依赖项(它将自动将define(definition)
转换为define(['Dependency'], definition)
)。
这里唯一的问题是保持文件的路径相同。请记住,嵌套的requires(if else)在Require(阅读文档)中不起作用,所以我不得不做一些类似的事情:
var dependency;
try {
dependency = require('./Dependency'); // node module in the same folder
} catch(err) { // it's not node
try {
dependency = require('Dependency'); // requirejs
} catch(err) { }
}
这对我来说非常有效。所有这些路径都有点棘手,但最终,你会将两个独立的模块放在不同的文件中,这些文件可以在两端使用,而无需任何类型的检查或破解-它们的所有依赖项都很有魅力:)
看看webpack bundler。您可以编写模块并通过模块导出进行导出。然后,您可以在服务器中使用module.export,并使用webpack进行浏览器构建。配置文件使用将是的最佳选择
module.exports = {
entry: "./myModule",
output: {
path: "dist",
filename: "myModule.js",
library: "myModule",
libraryTarget: "var"
}
};
这将获取myModule并将其导出到myModule.js文件中。模块内部将被分配给名为myModule(库标志)的var(libraryTarget标志)。
可以导出为commonJS模块、war、this、function
由于绑定是节点脚本,因此可以按语法设置此标志值。
看看externals标志。如果您希望对某些依赖项具有特殊行为,则会使用它。例如,您正在创建react组件,并且在您的模块中您希望需要它,但在为web绑定时却不需要,因为它已经存在了。
希望这就是你想要的。
- 如何捆绑commonjs模块,除非指定需要
- 如何使用angular js从2个表(在sql server中)中提取数据
- 如何在cloud9中向server.js发送post请求
- 使用谷歌地图、C#、ASP.net、SQL Server显示带有标记的地图.地图未显示
- AMD应用程序在浏览器中的加载速度是否快于CommonJS应用程序
- Gulp,浏览使用react作为CommonJS不起作用.React未定义
- 使用Javascript或SQL Server将Outlook电子邮件发送到SQL表
- 对CommonJS配置文件使用全局变量
- 如何在JSFiddle上使用CommonJS模块
- 在 api 文档中 socket.io“Server(srv:http#Server, opts:Object)”是什么
- 在引导程序中从 HTML 表单执行 Python (CGI) 文件.带有Apache Server的JS
- ExpressJS Server - 如何处理多个域
- 如何使用默认函数导出为 commonjs 模块创建类型
- 当我关联runat=“server”属性时,JQuery UI 按钮集在单选按钮上不起作用
- 节点.js集群模块不会在 http 上释放套接字/端口.Server.close().
- 如何使用 ajax 从 sql Server 获取单选按钮的值,并表示列表单选按钮
- jQuery: setInterval effects on the server?
- 如何在不刷新页面的情况下从 PHP 中的 SQL Server 数据库获取数据
- JavaScript Stack - Web Server 和 API Server:一起或分开
- 打包具有依赖关系的Browser/Server CommonJS模块