2013-11-23 9 views
43

这有点长,但我需要代码示例来说明我的困惑。这之后,我很感兴趣的答案如下:如何在多个grunt-browserify软件包中管理相对路径别名?

  1. 我如何使用require('module')代替require('../../src/module')require('./module')
  2. 如何重复使用./index.jsspec/specs.js而不重复工作? (并防止src/app.js由于它是入口模块而运行)。

我已经开始了几个基于浏览器的项目,并且爱着browserify和grunt。但是每个项目都会在我的开发/学习曲线中死去。一旦我将测试添加到组合中并且必须管理两个browserify捆绑包(app.jsspec/specs.js),整个系统就会崩溃。我将解释:

我用grunt-browserify,并设置我的初始目录:

. 
├── Gruntfile.js 
├── index.js (generated via grunt-browserify)  [1] 
├── lib 
│   ├── jquery 
│   │   └── jquery.js        [2] 
│   └── jquery-ui 
│    └── jquery-ui.js       [3] 
├── spec 
│   ├── specs.js (generated via grunt-browserify) [4] 
│   └── src 
│    ├── spec_helper.js (entry) 
│    └── module_spec.js (entry) 
└── src 
   ├── app.js (entry) 
   └── module.js 
  1. 使用一个条目文件(src/app.js),并做了代码走捆绑所有需要模块。
  2. 使用browserify-shim别名jquery
  3. 只是别名jquery-ui没有垫片(需要你后var $ = require('jquery'))。
  4. spec/src中的所有帮助程序和规格文件用作输入模块。

我会通过我的配置步骤:

browserify: { 
    dist: { 
    files: { 
     'index.js': ['src/app.js'] 
    } 
    } 
} 

// in app.js 
var MyModule = require('./module'); // <-- relative path required?! 

快乐

现在添加的jQuery:

browserify: { 
    options: { 
    shim: { 
     jquery: { 
     path: 'lib/jquery/jquery.js', 
     exports: '$' 
     } 
    }, 
    noParse: ['lib/**/*.js'], 
    alias: [ 
     'lib/jquery-ui/jquery-ui.js:jquery-ui' 
    ] 
    }, 
    dist: { 
    files: { 
     'index.js': ['src/app.js'] 
    } 
    } 
} 

// in app.js 
var $ = require('jquery'); 
require('jquery-ui'); 
var MyModule = require('./module'); 

快乐

现在添加规格:

options: { 
    shim: { 
    jquery: { 
     path: 'lib/jquery/jquery.js', 
     exports: '$' 
    } 
    }, 
    noParse: ['lib/**/*.js'], 
    alias: [ 
    'lib/jquery-ui/jquery-ui.js:jquery-ui' 
    ] 
}, 
dist: { 
    files: { 
    'app.js': 'src/app.js' 
    } 
}, 
spec: { 
    files: { 
    'spec/specs.js': ['spec/src/**/*helper.js', 'spec/src/**/*spec.js'] 
    } 
} 

// in app.js 
var $ = require('jquery'); 
require('jquery-ui'); 
var MyModule = require('./module'); 

// in spec/src/module_spec.js 
describe("MyModule", function() { 
    var MyModule = require('../../src/module'); // <-- This looks like butt!!! 
}); 

悲伤

总结:我如何...

  1. 使用require('module')而不是require('../../src/module')require('./module')
  2. 重用./index.js in spec/specs.js没有重复的工作? (并防止src/app.js由于它是入口模块而运行)。

回答

4

这些答案取决于您的项目其余部分的设置,但也许这是一个很好的起点。此外,您将需要使用grunt-browserify的当前v2测试版来实际运行(npm install [email protected])。

可以使用aliasMapping为你的模块创建一些动态的别名。为了清楚起见,我们将所有模块移动到src/modules/。然后,aliasMapping配置可以是这样的:

options: { 
    aliasMappings: { 
    cwd: 'src', 
    src: ['modules/**/*.js'] 
    } 
} 

让假设您在src/modules/magic/stuff.js一个模块,那么你可以要求它这样,无论是在做了需要的.js文件位于:

var magicStuff = require('modules/magic/stuff.js'); 

2.

不知道这一个。您的项目结构显示spec/index.js,但您提到spec/specs.js。他们应该是同一个文件吗?

无论如何,你在说什么重复的工作?因为./index.jsspec/index.js有不同的输入文件。如果您正在寻找将./index.js包含在specs/中的方法,那么也许您可以在运行测试之前将其复制,而不是从头开始构建它。

+0

'spec/index.js'与'spec/specs,js'是一个错字。编辑的问题。谢谢你的回答。似乎真相是原始的(旧版本)没有被设计来做这个设置。我认为更好的问题是*应该如何组织这样的项目?许多教程不捆绑生产脚本和测试脚本。添加testem之类的东西,难怪人们会感到困惑。我们需要一个元指南,将所有这些软件包和谐地整合在一起。 – Sukima

+1

根本问题可能是JS生态系统的多样性。它还很年轻。也许有一天重复的软件包/实用程序将停止共存,其中一个将成为解决X事务的默认资源。现在,谈到JS时,至少有2/3不同的库在做同样的事情。所以对于像构建系统这样的东西来说,特别难以完全不可知,并且对于所有可能的库组合来说都很好。 –

+0

这是'aliasMappings'选项特定于'grunt-browserify'还是它是一个'browserify'隐藏选项的包装?我试图用['opts.basedir'](https://github.com/substack/node-browserify#var-b--browserifyfiles-or-opts)选项获得相同的行为,但没有运气。 – eightyfive

29

答案很简单:

最简单的方法是使用browserify的paths选项。我用了它几个月,取得了巨大的成功。我甚至提出,使用此功能入门套件:https://github.com/stample/gulp-browserify-react-phonegap-starter

var b = browserify('./app', {paths: ['./node_modules','./src/js']}); 

路径 - require.paths数组,如果没有什么是对正常 发现使用node_modules递归步行

如果你有src/js/modulePath/myModule.js中的文件不允许您在任何其他源文件中编写require("myModule"),而是require("modulePath/myModule")

弃用选项?

它似乎并不如此!

Browserify模块分辨率算法镜像resolution algorithm in NodeJS。 Browserify的paths选项因此是用于NodeJS的NODE_PATH env变量行为的镜像。 Browserify作者(substack)在本SO主题中声称NODE_PATH选项在NodeJS中已被弃用,因此它在Browserify中也被弃用,并且可能在下一版本中被删除。

我不同意这个说法。

请参阅NODE_PATH文档。没有提到该选项已被弃用。但是仍然有一个有趣的提到,确实在亚组的要求的方向:

你非常鼓励本地将您的依赖关系 node_modules文件夹。他们将更快,更可靠地加载。

this question已于2012年发布在邮件列表中。

Oliver Leics: is NODE_PATH deprecated? 
Ben Noordhuis (ex core NodeJS contributor): No. Why do you ask? 

如果事情不解决的NodeJS算法中移除,我不认为它会很快从Browserify :)

结论

您可以使用paths选项删除或者把你的代码放在node_modules之类的官方文档和Browserify author recommends

就个人而言,我不喜欢这个主意,把自己的代码中node_modules我只是保持这个整个文件夹我的源代码控制的。我在几个月内使用了paths选项,并且根本没有任何问题,并且我的构建速度非常好。

把一个符号内node_modules可能是方便,但不幸的是,我们已经与Windows在这里工作的开发人员的亚组的解决方案......

我认为不过有,你不想使用paths选项的情况下,:当您正在开发在其他应用程序需要的NPM存储库上发布的库时。你真的不希望这些库客户端必须设置特殊的构建配置,只是因为你想避免lib中的相对路径地狱。

另一个可能的选择是使用remapify

+2

刚刚遇到这个线程,这个选项对于当前的browserify/grunt-browserify来说更好。有关它在grunt-browserify(已验证)中的外观示例,请参见:http://cl.ly/VXyx(注意路径在browserify选项下) –

+0

其他人在Browserify 8.1中使用'paths'时看到了问题0.1?我一直在看“无法找到模块”消息,并恢复到8.0.1。 – Cory

6

一切答案在这里有关别名和opts.paths/$NODE_PATH都不是很大,因为这种方法是在节点的模块系统的过时的部分和browserify,所以它可能停止工作任何时候。

你应该学习how the node_modules algorithm works,这样你就可以有效地组织你的代码,并且可以很好地嵌套node_modules目录。

有在覆盖avoiding ../../../../../../..相对路径问题browserify手册的部分。这可以概括为:

  • 把内部模块化的代码在node_modules/node_modules/app这样就可以require('yourmodule')require('app/yourmodule'),这取决于你喜欢。
  • 如果您正在为非Windows平台开发,那么您可以使用符号链接,而这正是您喜欢的。

请勿使用opts.path/$NODE_PATH。它使你的项目:

  • 隐式依赖于一个非显而易见性配置或环境设置
  • 困难,使在这两个节点和浏览器
  • 容易模块系统中的变化工作,数组的路径已被弃用在节点和browserify
+0

感谢您的见解。你知道为什么'opts.path'已被弃用吗?我不喜欢使用弃用的解决方案,但我认为这个弃用的选项比将代码放在'node_modules'中方便得多。你知道它为什么被弃用吗?任何github问题?我找不到任何 –

+0

顺便说一句,在官方文档(http://nodejs.org/api/modules.html)上,我们可以这样读:'为了使模块可用于节点REPL,它可能是有用的还要将/ usr/lib/node_modules文件夹添加到$ NODE_PATH环境变量中。由于使用node_modules文件夹的模块查找都是相对的,并且根据调用require()的文件的实际路径,软件包本身可以位于任何位置。请告诉我们您在哪里看到它已被弃用,因为正式文档并不反映这一点。 –

+0

好的,所以我在这里找到了一些你在说的内容:http://nodejs.org/api/all.html#all_loading_from_the_global_folders。 '这些主要是出于历史原因。强烈建议您将您的依赖项本地放置在node_modules文件夹中。他们会更快,更可靠地加载。“这是一个建议,但实际上并没有说该功能已被弃用,可能会被删除。根据这个ML讨论,它也不被弃用:https://groups.google.com/forum/#!topic/nodejs/EENwg8GAJd8 –

1

我认为最好的方法是像Sebastien Lorber指出的那样,通过管道调用browserify来设置路径。

但与最新版本browserify的,(因为这一刻,这是[email protected])路径变量存储路径是Browserify将用于它的进程。因此,设置路径变量将排除说......您的节点的全局文件夹,据我所知。因此,你需要一个Gulp任务,看起来像这样:

gulp.task('reactBuild', function() { 
    return gulp.src(newThemeJSX) 
    .pipe(browserify({ 
     debug: true, 
     extensions: ['.jsx', '.js', '.json'], 
     transform: [reactify], 
     paths: ['../base_folder/node_modules', '/usr/lib/node_modules'] 
    })) 
    .pipe(gulp.dest(newThemeBuilt)) 
    .on('error', function(error) { 
     console.log(error); 
    }); 
}); 
相关问题