45

这有点长,但我需要代码示例来说明我的困惑。之后我对以下问题的答案感兴趣:

  1. 我如何使用require('module')代替require('../../src/module')or 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在不重复spec/specs.js工作的情况下重复使用?(并防止src/app.js运行,因为它是一个入口模块)。
4

4 回答 4

30

简单的回答:

最简单的就是使用pathsbrowserify的选项。我使用它几个月并取得了巨大的成功。我什至制作了一个使用此功能的入门工具包:https ://github.com/stample/gulp-browserify-react-phonegap-starter

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

路径 - 如果在正常的 node_modules 递归遍历中找不到任何内容,则使用 require.paths 数组

如果您有一个文件,src/js/modulePath/myModule.js则不会让您在任何require("myModule")地方写入,而是require("modulePath/myModule")从您的任何其他源文件中写入。

已弃用的选项?

好像不是这样!

Browserify 模块解析算法反映了 NodeJS 中的解析算法。因此,Browserify的paths选项是 NodeJS 环境NODE_PATH变量行为的镜像。Browserify 作者(子堆栈)在此 SO 主题中声称该NODE_PATH选项在 NodeJS 中已弃用,因此它在 Browserify 中也已弃用,并且可以在下一个版本中删除。

我不同意这种说法。

请参阅NODE_PATH文档。没有提及该选项已被弃用。然而,仍然有一个有趣的提及是在子堆栈声明的方向上:

强烈建议您将依赖项本地放置在 node_modules 文件夹中。它们将被更快、更可靠地加载。

这个问题已于 2012 年发布在邮件列表中。

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

如果在 NodeJS 解析算法中没有删除某些东西,我认为它不会很快从 Browserify 中删除:)

结论

您可以使用paths选项,也可以node_modules像官方文档和Browserify 作者推荐的那样将您的代码放入其中。

就个人而言,我不喜欢将自己的代码放入其中,node_modules因为我只是将整个文件夹置于我的源代码控制之外。我使用该paths选项几个月了,完全没有任何问题,而且我的构建速度非常好。

子堆栈在内部放置符号链接的解决方案node_modules可能很方便,但不幸的是,我们有开发人员在这里使用 Windows...

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

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

于 2014-05-12T11:58:12.237 回答
7

这里关于别名和opts.paths/的所有答案$NODE_PATH都不是很好,因为这种方法是 node 和 browserify 中模块系统的已弃用部分,因此它可能随时停止工作。

你应该学习node_modules 算法是如何工作的,这样你就可以有效地组织你的代码,使其与嵌套node_modules目录配合得很好。

browserify 手册中有一节介绍了避免 ../../../../../../..相对路径问题。可以概括为:

  • 将您的内部模块化代码放入node_modules/或放置,node_modules/app以便您可以require('yourmodule')require('app/yourmodule')根据您的喜好。
  • 如果您正在为非 Windows 平台开发,您可以使用符号链接,这就是您喜欢的。

不要使用opts.path/ $NODE_PATH。它使您的项目:

  • 隐式依赖于不明显的配置或环境设置
  • 更难在节点和浏览器中工作
  • 容易受到模块系统更改的影响,因为在 node 和 browserify 中不推荐使用数组路径
于 2014-08-13T21:47:08.270 回答
4

这些答案取决于您项目的其余部分是如何设置的,但也许这是一个很好的起点。此外,您将需要使用当前 v2 测试版的 grunt-browserify 才能实际工作(npm install grunt-browserify@2)。

1.

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

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

假设您有一个模块src/modules/magic/stuff.js,那么您可以像这样 require 它,而不管执行 require 的 .js 文件位于何处:

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

2.

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

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

于 2014-03-01T12:42:27.090 回答
1

正如 Sebastien Lorber 所指出的,我认为绝对最好的方法是通过管道设置您调用 browserify 的路径。

但是对于最新版本的 browserify,(截至目前,即browserify@11.0.0) path 变量存储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);
    });
});
于 2015-07-22T17:49:09.580 回答