如何在多个grunt-browserify包中管理相对路径别名?

时间:2013-11-23 04:05:58

标签: gruntjs browserify

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

  1. 如何使用require('module')代替require('../../src/module')require('./module')
  2. 如何在./index.js中重复使用spec/specs.js而不重复工作? (并阻止src/app.js运行,因为它是一个入口模块。)
  3. 我已经启动了几个基于浏览器的项目并且喜欢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中的所有帮助程序和规范文件作为条目模块。
    5. 我将逐步完成配置:

      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 个答案:

答案 0 :(得分:30)

简单回答:

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

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

paths - 如果在法线上找不到任何内容,则使用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主题中声称在NodeJS中不推荐使用NODE_PATH选项,因此在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

答案 1 :(得分:7)

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

您应该了解how the node_modules algorithm works,以便能够以与嵌套node_modules目录配合良好的方式有效地组织代码。

browserify手册中有一节涵盖avoiding ../../../../../../..相对路径问题。它可以概括为:

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

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

  • 隐含地依赖于非显而易见的配置或环境设置
  • 更难在节点和浏览器中工作
  • 容易受到模块系统更改的影响,因为在node和browserify中不推荐使用数组路径

答案 2 :(得分:4)

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

<强> 1

您可以使用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.js的条目文件与spec/index.js不同。如果您正在寻找在./index.js中包含specs/的方法,那么也许您可以在运行测试之前复制它,而不是从头开始构建它。

答案 3 :(得分:1)

我认为绝对最好的方法是,正如Sebastien Lorber所说,通过管道设置浏览器化的路径。

但是使用最新版本的browserify(截至当前,即browserify@11.0.0),路径变量存储了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);
    });
});
相关问题