如何在使用第三方所需的东西时保持 Browserify 包大小合理(如果重要,通过 grunt)

How to keep Browserify bundle size sensible when using requires for thirdparty stuff (via grunt if it matters)

我正在尝试捆绑我自己的代码 (A),该代码又使用 2 个第三方组件(B 和 C),其中 C 也需要 B。据我所知,所有内容都是使用 CommonJS 节点样式模块编写的.

A 单独打包时为 60K。

B 是单独包含的并且假定是全局的,我通过在我的构建步骤中做一些肮脏的替换将 require("B") 替换为 global.B

C 是导致我出现问题的原因,它的大小应该是 "just 8K",但是当我尝试将它与 A 捆绑在一起时,我的捆绑包会跳升至 600K+,因为我认为它会产生大量的依赖性?

这是不可接受的,但我不知道如何让它变小,因为我不知道它到底在拉什么(或者更重要的是我可以排除什么以使其仍然有效)。我可以尝试使用排除项进行二元分割,但我不知道这是否是一种安全的方法,甚至是明智的方法。

我怎样才能将 C 捆绑起来,并且只有 68.5K(两个代码块的总大小为 60k + 8.5k)才能打包出来,当然还能工作?

我是 node 和 browserify 的新手,但我已经研究了一个多星期了,可以这么说,在举手之前我已经试过了。

其他信息(如果重要):

如果您创建一个包含 所有 您应用的依赖项 (B + C) 的外部包,并在捆绑您的应用自己的代码 (A) 时将这些模块声明为外部模块,那么事情应该工作如你所愿。

我不知道执行此操作的 grunt-browserify 配置咒语,但下面显示了如何在某些示例 gulp 任务中直接使用 browserify,因此包创建应该是可重用的:

var browserify = require('browserify')
var gulp = require('gulp')
var source = require('vinyl-source-stream')

gulp.task('js-deps', function() {
  var b = browserify()
  b.require('react')
  b.require('react-router-component')
  b.transform('envify')

  return b.bundle()
    .pipe(source('deps.js'))
    .pipe(gulp.dest('./build'))
})

gulp.task('bundle-js', function() {
  var b = browserify('./lib/app.js')
  b.external('react')
  b.external('react-router-component')

  return b.bundle()
    .pipe(source('app.js'))
    .pipe(gulp.dest('./build'))
})

其他人已经提到了应该是实际解决方案的外部选项。现在,也请考虑这些建议。您可能已经了解大部分(如果不是全部)但其中一些可能会有所帮助。这不会将 600k 文件变成 1k,但可能仍然很重要。

首先检查 https://github.com/substack/node-browserify#usage 中的高级选项,更具体地说是 --no-bundle-external 选项。如果外部选项确实适用于 require('b') 但仍包含外部库,那么这是你最好的选择;

还要查看有关全局变量的选项。当我开始使用 browserify 时,我将一个函数编译成一个巨大的库,因为它包含了 NodeJS 本机模块的所有存根。上述选项是解决此问题的关键。它在一个 Grunt 任务中,但如果我没记错的话它不在 grunt-browserify 任务中,它仍然可能是相关的。

如果您还没有设置构建环境,请务必在 运行 browserify:app 之前设置。有些库依赖于这些变量来进行生产编译(我认为 React 就是其中之一)。

    grunt.loadNpmTasks('grunt-env');

    // initConfig task
    env: {
      dist: {
        NODE_ENV : 'production',
      },
      dev: {
        NODE_ENV: 'development',
      } 
    }

    grunt.registerTask("build_dist", ['env:dist', 'browserify:app']

尝试 运行 Uglify 也特别使用这些选项;

    // initConfig task options
    options: {
      compress:{
        dead_code     : true,  // discard unreachable code
        drop_debugger : true,  // discard “debugger” statements
        global_defs   : {      // global definitions
          "DEBUG": false,      // matters for some libraries
        },
      }
    }

您可以优化更多,但这应该让您入门。

B is included separately and assumed to be global, I've got this working just fine by doing a dirty bit of a replace in my build step that swaps out require("B") with global.B.

如果您在编译后切换到 global.B,您的包也将具有所有 require('b') 的依赖项。这个技巧(可能)更好:

This is not acceptable but I don't know how to get it any smaller as I don't know what the heck its pulling in (or more importantly what I can exclude to make it still work)

查看生成库的源代码,你应该能够识别不同的模块及其文件路径。

我整理了一个工作示例,说明如何使用 Browserify 将代码拆分为多个包:https://github.com/aldendaniels/browserify-bundle-splitting

使用这种方法,您可以通过 Browserify 加载所有供应商代码(不需要全局填充),但仍然单独捆绑了您自己的代码。

由于生成的包是真正独立的,您可以轻松地对生成的包进行不同的设置。例如,您可能希望为第 3 方代码禁用源映射,但为您自己的代码使用源映射。

您可以通过 运行 此命令查看捆绑包中哪些文件正在占用 space:browserify --list test/browser/browserify-test-uncompiled.js | xargs ls -la | sort