Как сохранить разумный размер пакета Browserify при использовании требований для сторонних материалов (через grunt, если это имеет значение)

Я пытаюсь связать свой собственный код (A), который, в свою очередь, использует 2 сторонних компонента (B и C), где C также нуждается в B. Насколько я знаю, все написано с использованием модулей стиля узла CommonJS.

А сам по себе в комплекте выходит 60К.

B включен отдельно и считается глобальным, у меня это отлично работает, выполнив грязную замену на моем этапе сборки, которая заменяет require("B") на global.B

C - это то, что вызывает у меня проблемы, хотя его размер должен быть «всего 8 КБ», но когда я пытаюсь объединить его с A, мой пакет подскакивает до 600 КБ +, поскольку я предполагаю, что он тянет в изобилии зависимости?

Это неприемлемо, но я не знаю, как сделать его еще меньше, поскольку я не знаю, какого черта он тянет (или, что более важно, что я могу исключить, чтобы он все еще работал). Я мог бы попробовать бинарную отбивку с исключениями, но я не знаю, безопасный ли это способ или даже разумный способ сделать это.

Как я могу связать C так, чтобы мой пакет получился только 68,5 КБ (общий размер обоих фрагментов кода 60 КБ + 8,5 КБ) и, конечно, все еще работал?

Я новичок в узле и браузере, но я бился над этим больше недели, так что честно скажу, что я дал ему хороший удар, прежде чем поднять руку.

Дополнительная информация, если это важно:

  • он должен работать на стороне сервера и на стороне клиента
  • B на самом деле ReactJS
  • C на самом деле является компонентом маршрутизатора React
  • Использование Windows и C# через ReactJS.net... эй... подожди... вернись... перекати-поле

person Pete Duncanson    schedule 13.01.2015    source источник
comment
Потребуется дополнительная информация о коде/командах, которые вы используете для связывания кода. Я объединяю свой код в 2 файла, library.js и application.js, и я могу ограничить свой файл application.js только реальным пользовательским кодом приложения.   -  person ryanzec    schedule 13.01.2015
comment
Связанные проблемы, кажется, это проблема со ссылками на модули React-router-component глубоко внутри React, из-за чего htem втягивается в мой пакет: github.com/STRML/react-router-component/issues/2   -  person Pete Duncanson    schedule 15.01.2015


Ответы (4)


Если вы создадите внешний пакет, содержащий все зависимости вашего приложения (B + C), и объявите эти модули внешними при объединении собственного кода вашего приложения (A), все должно работать так, как вы ожидаете.

Я не знаю заклинаний конфигурации grunt-browserify для этого, но ниже показано, как вы будете использовать browserify напрямую в некоторых примерах gulp-задач, поэтому создание пакета должно быть многоразовым:

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'))
})
person Jonny Buchanan    schedule 13.01.2015
comment
Я играл с внешними данными, моя проблема по-прежнему заключается в общем размере пакета. 600K за что-то, я думаю, должно быть только около 1/8 от этого, что вызывает у меня некоторую царапину в голове. Имея внешние файлы размером 540 КБ и мой пакет на 60 КБ, все еще требуется много кода для отправки на клиентскую сторону :( - person Pete Duncanson; 14.01.2015
comment
600 КБ звучит правильно для неминифицированного React и некоторых других зависимостей. "nofollow noreferrer">deps для react-hn составляет ~933 КБ. Используя process.env.NODE_ENV = 'production', преобразование envify и UglifyJS для производственной сборки, это сокращается до ~ 344 КБ, что составляет ~ 120 КБ, заархивированных по сети. - person Jonny Buchanan; 15.01.2015
comment
Я знаю, но он уже должен быть доступен через отдельный «скрипт» на стороне клиента и внедрен на стороне сервера. Надеялся избежать двойного удара, поскольку это вызывает проблемы. - person Pete Duncanson; 15.01.2015
comment
Похоже, это browerify-shim, который вам нужен, но я не использовал его на зависимости моих зависимостей раньше, только собственные зависимости моего приложения. - person Jonny Buchanan; 15.01.2015

Кто-то уже упомянул внешний вариант, который должен быть фактическим решением. А теперь примите во внимание и эти советы. Возможно, вы уже знаете большую часть, если не все, но кое-что может помочь. Это не превратит файл размером 600 КБ в 1 КБ, но, тем не менее, может иметь большое значение.

Начните с проверки дополнительных параметров в 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 включен отдельно и считается глобальным, у меня это работает отлично, выполнив грязную замену на моем этапе сборки, которая заменяет require("B") на global.B.

Если вы переключаетесь на global.B после компиляции, ваш пакет также будет иметь все зависимости require('b'). Этот хак (вероятно) лучше:

  • Перейдите на страницу https://github.com/jmreidy/grunt-browserify.
  • CTRL+F "переназначить"
  • Реализуйте это, чтобы оно указывало на b-singleton.js
  • Содержимое b-singleton.js:

    module.exports = window.B;
    

Это неприемлемо, но я не знаю, как сделать его еще меньше, поскольку я не знаю, какого черта он тянет (или, что более важно, что я могу исключить, чтобы он все еще работал)

Загляните внутрь исходного кода сгенерированной библиотеки, вы сможете идентифицировать различные модули и их пути к файлам.

person Chris B.    schedule 13.01.2015

Я собрал рабочий пример того, как разделить код на несколько пакетов с помощью Browserify: https://github.com/aldendaniels/browserify-bundle-splitting

При таком подходе вы можете загрузить весь свой код поставщика через Browserify (глобальное шиммирование не требуется), но при этом иметь свой собственный код, связанный отдельно.

Поскольку сгенерированные пакеты действительно независимы, вы можете легко задать разные настройки для сгенерированных пакетов. Например, вы можете отключить исходные карты для стороннего кода, но использовать исходные карты для своего собственного кода.

person alden    schedule 18.05.2015

Вы можете увидеть, какие файлы занимают место в пакете, выполнив эту команду: browserify --list test/browser/browserify-test-uncompiled.js | xargs ls -la | sort

person Fergie    schedule 12.09.2016