Browserify - Как вызвать функцию, связанную с файлом, созданным с помощью браузера в браузере

Я новичок в nodejs и браузере. Я начал с этой ссылки .

У меня есть файл main.js, который содержит этот код

var unique = require('uniq');

var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];

this.LogData =function(){
console.log(unique(data));
};

Теперь я устанавливаю модуль uniq с помощью npm:

 npm install uniq

Затем я объединяю все необходимые модули, начиная с main.js, в один файл с именем bundle.js с помощью команды browserify:

browserify main.js -o bundle.js

Сгенерированный файл выглядит следующим образом:

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var unique = require('uniq');

var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];

this.LogData =function(){
console.log(unique(data));
};

},{"uniq":2}],2:[function(require,module,exports){
"use strict"

function unique_pred(list, compare) {
  var ptr = 1
    , len = list.length
    , a=list[0], b=list[0]
  for(var i=1; i<len; ++i) {
    b = a
    a = list[i]
    if(compare(a, b)) {
      if(i === ptr) {
        ptr++
        continue
      }
      list[ptr++] = a
    }
  }
  list.length = ptr
  return list
}

function unique_eq(list) {
  var ptr = 1
    , len = list.length
    , a=list[0], b = list[0]
  for(var i=1; i<len; ++i, b=a) {
    b = a
    a = list[i]
    if(a !== b) {
      if(i === ptr) {
        ptr++
        continue
      }
      list[ptr++] = a
    }
  }
  list.length = ptr
  return list
}

function unique(list, compare, sorted) {
  if(list.length === 0) {
    return []
  }
  if(compare) {
    if(!sorted) {
      list.sort(compare)
    }
    return unique_pred(list, compare)
  }
  if(!sorted) {
    list.sort()
  }
  return unique_eq(list)
}

module.exports = unique
},{}]},{},[1])

После включения файла bundle.js в мою страницу index.htm, как мне вызвать функцию logData??


person SharpCoder    schedule 25.04.2014    source источник
comment
Куда вы хотите позвонить? А почему ты хочешь его назвать?   -  person artur grzesiak    schedule 25.04.2014
comment
@arturgrzesiak: я хочу использовать эту функцию в одном из моих других проектов, которые я буду запускать в браузере.   -  person SharpCoder    schedule 26.04.2014


Ответы (12)


По умолчанию браузер не позволяет вам получить доступ к модулям из-за пределов браузерного кода — если вы хотите вызвать код в браузерном модуле, вы должны браузерировать свой код вместе с модулем. Примеры см. на странице http://browserify.org/.

Конечно, вы также можете явно сделать свой метод доступным извне, например:

window.LogData =function(){
  console.log(unique(data));
};

Затем вы можете позвонить LogData() из любого места на странице.

person thejh    schedule 25.04.2014
comment
Спасибо. Это работает. Означает ли это, что при создании функций вместо this.functionName я должен писать window.functionName? Есть ли у нас какие-либо другие работы для этого? Есть ли причины использовать window.functionName? - person SharpCoder; 27.04.2014
comment
@Brown_Dynamite В браузере все, что вы прикрепляете к объекту window, может быть доступно из любого места на веб-странице. - person thejh; 27.04.2014
comment
Спасибо. Это имеет смысл. Есть ли работа вокруг? в противном случае, прежде чем я просмотрю свой код, я должен добавить window. перед всеми функциями, которые мне нужно выставить. - person SharpCoder; 27.04.2014
comment
Рекомендуется избегать подобного загрязнения окон; особенно потому, что вы привязываете свои компоненты на основе памяти к области, которая не удаляется (или имеет разумный жизненный цикл). - person deepelement; 13.08.2015
comment
вы должны браузерировать свой код вместе с модулем - Эх, а что, если я захочу сделать что-то вроде onclick="someFunction()". Вы не можете утверждать, что это редкий вариант использования!?! - person BlueRaja - Danny Pflughoeft; 13.08.2015
comment
@BlueRaja-DannyPflughoeft, конечно, не редкость, но несколько грязный, особенно если учесть, что он несовместим с безопасной политикой безопасности контента. - person thejh; 13.08.2015
comment
Существует серьезная нехватка документации для начинающих о том, как на самом деле использовать Browserify на клиенте. - person Oliver Dixon; 19.12.2015
comment
да, в документации должно быть четко указано, что это проектное решение, которого следует избегать, но должен быть указан четкий путь, чтобы заставить его работать, когда у вас нет альтернативы (в моем случае использование данных из шаблона для заполнения объекта JS) ... спасибо @thejh за указание на простое решение! ;) - person Alexandre Martini; 14.08.2016
comment
Я даже не могу представить себе ситуацию, когда вы НЕ ХОТЕЛИ бы сделать свои основные функции доступными вне модуля. Как это не поведение по умолчанию? Какое веб-приложение не вызывает функции? - person Cybernetic; 31.03.2020

Ключевой частью объединения автономных модулей с Browserify является параметр --s. Он предоставляет все, что вы экспортируете из своего модуля, используя узел module.exports в качестве глобальной переменной. Затем файл можно включить в тег <script>.

Вам нужно сделать это только в том случае, если по какой-то причине вам нужно, чтобы эта глобальная переменная была открыта. В моем случае клиенту требовался автономный модуль, который можно было бы включить в веб-страницы, не беспокоясь об этом бизнесе Browserify.

Вот пример, где мы используем опцию --s с аргументом module:

browserify index.js --s module > dist/module.js

Это сделает наш модуль глобальной переменной с именем module.
Источник.

Обновление: спасибо @fotinakis. Убедитесь, что вы проезжаете --standalone your-module-name. Если вы забудете, что --standalone принимает аргумент, Browserify может молча сгенерировать пустой модуль, поскольку не может его найти.

Надеюсь, это сэкономит вам время.

person Matas Vaitkevicius    schedule 02.03.2015
comment
Я пытаюсь браузерировать код ES6 с кодом детализации. Но автономный объект пуст, когда я пытаюсь его утешить в браузере. Простой код ES6 без каких-либо модулей отлично работает в автономном режиме. Любые указатели на это? - person John; 18.03.2016
comment
@jackyrudetsky понятия не имею, я бы порекомендовал добавить вопрос на SO, звучит как интересная проблема. может быть связано с этим. github.com/substack/node-browserify/issues/1357 - person Matas Vaitkevicius; 18.03.2016
comment
@jackyrudetsky Убедитесь, что вы проходите --standalone your-module-name. Если вы забудете, что --standalone принимает аргумент, browserify может молча сгенерировать пустой модуль, так как не сможет его найти. - person fotinakis; 20.05.2016
comment
@fotinakis На самом деле это была проблема в Browserify github.com/substack/node-browserify/issues /1537 - person John; 23.05.2016
comment
ИМО, это должен быть принятый ответ. Если вы используете глобальную функцию, гораздо лучше иметь собственное пространство имен, чем вывешивать каждую функцию из окна. - person VictorB; 04.10.2016
comment
Работает как шарм! - person LEMUEL ADANE; 02.03.2018
comment
@VictorB все глобальные переменные в Javascript являются элементами окна, поэтому оба метода достигают одного и того же (добавление глобальных переменных в окно) - person David Lopez; 10.01.2019
comment
@MatasVaitkevicius Большое спасибо, это спасло меня от многочасовой головной боли. - person jlewkovich; 11.02.2019
comment
Это лучший ответ. - person parttimeturtle; 07.04.2020

Ответ @Matas Vaitkevicius с автономной опцией Browserify является правильным (@thejh ответ с использованием глобальной переменной окна также работает, но, как и другие отметил, что он загрязняет глобальное пространство имен, поэтому он не идеален). Я хотел добавить немного больше деталей о том, как использовать автономную опцию.

В исходном скрипте, который вы хотите связать, обязательно укажите функции, которые вы хотите вызывать, через module.exports. В клиентском скрипте вы можете вызывать эти открытые функции через ‹bundle-name›.‹func-name›. Вот пример:

В моем исходном файле src/script.js будет следующее:
module.exports = {myFunc: func};

Моя команда браузера будет выглядеть примерно так:
browserify src/script.js --standalone myBundle > dist/bundle.js

И мой клиентский скрипт dist/client.js загрузит связанный скрипт
<script src="bundle.js"></script>
, а затем вызовет открытую функцию следующим образом:
<script>myBundle.myFunc();</script>


Нет необходимости запрашивать имя пакета в клиентском сценарии перед вызовом открытых функций, например. <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script> не нужен и не будет работать.

На самом деле, как и все функции, связанные с browserify без автономного режима, функция require не будет доступна вне связанного скрипта. Browserify позволяет вам использовать некоторые функции Node на стороне клиента, но только в самом связанном скрипте; он не предназначен для создания автономного модуля, который вы можете импортировать и использовать где угодно на стороне клиента, поэтому нам приходится прибегать ко всем этим дополнительным проблемам, чтобы просто вызвать одну функцию вне ее связанного контекста.

person Galen Long    schedule 04.04.2017
comment
Ух ты! Наконец практический пример. - person N73k; 18.09.2018
comment
Хороший пример, но поскольку он загрязняет глобальное пространство имен, поэтому не идеальный не следует автоматически, он может быть приемлемым, если это только одна функция; Просто дым и зеркала, даже myBundle привязывается к объекту окна, window.myBundle.myFunc() вместо window.myFunc() - person joedotnot; 14.11.2019
comment
Должны быть дополнительные баллы для людей, которые приводят сквозные примеры. - person Sharud; 12.12.2019
comment
Вот как должна быть написана документация - person Ellery Leung; 11.05.2020
comment
Не работает на моей стороне, это мой пост. - person Antonio Ooi; 22.12.2020

Я только что прочитал ответы и, похоже, никто не упомянул об использовании глобальной переменной? Это полезно, если вы хотите использовать один и тот же код в node.js и в браузере.

class Test
{
  constructor()
  {
  }
}
global.TestClass = Test;

Затем вы можете получить доступ к TestClass из любого места.

<script src="bundle.js"></script>
<script>
var test = new TestClass(); // Enjoy!
</script>

Примечание. После этого TestClass становится доступным везде. Это то же самое, что использовать переменную окна.

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

person DDD    schedule 13.05.2017
comment
Как вы сами говорите, добавление функции к global дает тот же эффект, что и добавление к window, о чем уже писал jh. Этот ответ не добавляет новой информации. - person Galen Long; 05.05.2018
comment
@GalenLong, может быть, вы забыли, что в node.js нет переменной окна? И некоторые библиотеки, предназначенные для узлов и браузеров, могут вместо этого использовать глобальные. Мой ответ получил несколько голосов и еще не в минусе, поэтому я думаю, что он информативен для других, если не для вас. - person DDD; 06.05.2018
comment
Ты прав, @Azarus. На странице было еще два повторяющихся ответа, и я неправильно включил ваш в группу. Мои извенения. - person Galen Long; 07.05.2018
comment
просто хочу отметить, что висячие скобки здесь - очень плохая практика для javascript, например: примените этот шаблон к ключевому слову return и приготовьтесь плакать. например return {}, но опустите открывающую фигурную скобку на следующую строку. - person Sgnl; 29.09.2018
comment
@Sgnl, я понятия не имею, о чем ты говоришь, извини. Можете ли вы уточнить? - person DDD; 30.09.2018
comment
@Azarus Я создал скрипт, чтобы продемонстрировать, что я имею в виду - jsfiddle.net/cubaksot/1 - person Sgnl; 14.01.2019
comment
Я могу только сказать, что незнание синтаксиса javascript и сохранение фигурных скобок в новой строке не имеет ничего общего с плохой практикой. Фигурные скобки в новой строке на самом деле делают код более читаемым, имхо. Но вам решать, как вы пишете свой код, и это не имеет ничего общего с качеством ответа. Это действительно вкладки или пробелы - person DDD; 19.07.2019
comment
@Azarus, за исключением того, что в данном случае это не предпочтение, в моем примере jsfiddle он ломает код, я имею в виду, что он дает неожиданные результаты. С аргументом Spaces vs. tabs, по крайней мере, ваш код не сломан. Если вы перетащите открывающую скобку на следующую строку после оператора ключевого слова return, ваш объект (или массив, или любой открывающий токен...) НЕ будет возвращен из функции. это проблема именно того, как Javascript и ключевое слово return работают с этим стилем форматирования кода. - person Sgnl; 20.07.2019
comment
@Azarus На самом деле, если вы вернетесь к jsfiddle сейчас, вы увидите, что на месте есть линтер, и он вызывает разрыв строки после оператора return. - person Sgnl; 20.07.2019
comment
Вы не ставите фигурные скобки в новой строке для оператора возврата? И вы можете поставить фигурные скобки в новой строке после определения функции? - person DDD; 20.07.2019
comment
Вы спорите ... Пожалуйста, перестаньте беспокоиться об этом, это не добавляет ценности ответу. - person DDD; 20.07.2019
comment
@Azarus, как создать декоратор, который выставляет класс? согласно последней части вашего ответа. - person joedotnot; 14.11.2019
comment
взгляните на декораторы машинописного текста, это довольно просто. Или создайте вопрос, и я отвечу там с примерами кода. Канал здесь просто не тот. - person DDD; 14.11.2019

Прочтите README.md браузера о параметре --standalone или погуглите "browserify umd"

person undoZen    schedule 01.07.2014
comment
Это скорее подсказка, где найти ответ, чем ответ. - person user2314737; 01.07.2014
comment
это привело меня к решению, которое я искал в течение двух дней (как использовать вывод браузера из среды require.js). Спасибо! - person Flion; 26.08.2014

Минимальный запускаемый пример

Это в основном то же самое, что и: https://stackoverflow.com/a/43215928/895245, но с конкретными файлами, которые будут позволит вам просто запустить и легко воспроизвести его самостоятельно.

Этот код также доступен по адресу: https://github.com/cirosantilli/browserify-hello-world

index.js

const uniq = require('uniq');

function myfunc() {
  return uniq([1, 2, 2, 3]).join(' ');
}
exports.myfunc = myfunc;

index.html

<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Browserify hello world</title>
</head>
<body>
<div id="container">
</body>
</div>
<script src="out.js"></script>
<script>
document.getElementById('container').innerHTML = browserify_hello_world.myfunc();
</script>
</html>

Использование Node.js:

#!/usr/bin/env node

const browserify_hello_world = require('./index.js');

console.log(browserify_hello_world.myfunc());

Создайте out.js для использования в браузере:

npx browserify --outfile out.js --standalone browserify_hello_world index.js

И браузер, и командная строка показывают ожидаемый результат:

1 2 3

Протестировано с Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 17.12.2019
comment
Часть exports.myfunc.= myfunc была абсолютно критической и пропущена в других ответах. - person parttimeturtle; 07.04.2020

Чтобы ваша функция была доступна как из HTML, так и из узла на стороне сервера:

main.js:

var unique = require('uniq');

function myFunction() {
    var data = [1, 2, 2, 4, 3];
    return unique(data).toString();
}
console.log ( myFunction() );

// When browserified - we can't call myFunction() from the HTML, so we'll externalize myExtFunction()
// On the server-side "window" is undef. so we hide it.
if (typeof window !== 'undefined') {
    window.myExtFunction = function() {
        return myFunction();
    }
}

main.html:

<html>
    <head>
        <script type='text/javascript' src="bundle.js"></script>
    <head>
    <body>
        Result: <span id="demo"></span>
        <script>document.getElementById("demo").innerHTML = myExtFunction();</script>
    </body>
</html>

Выполнить:

npm install uniq
browserify main.js > bundle.js

и вы должны получить те же результаты при открытии main.html в браузере, что и при запуске

node main.js
person Ori Miller    schedule 08.08.2019

это действительно просто - вся эта концепция заключается в упаковке

1. альтернатива - объект "это"

для этой цели я предполагаю, что у вас есть только 1 скрипт для всего приложения {{app_name}} и 1 функция {{function_name}}

добавьте функцию {{function_name}}, чтобы возразить против этого

function {{function_name}}(param) {}
->
this.{{function_name}} = function(param) {}

тогда вам нужно назвать этот объект, чтобы он был доступен - вы сделаете это, добавив автономный параметр с именем, как советовали другие

поэтому, если вы используете watchify with browserify, используйте это

var b = browserify({
    ...
    standalone: '{{app_name}}'
});

или командная строка

browserify index.js --standalone {{app_name}} > index-bundle.js

то вы можете вызвать свою функцию из браузера

{{app_name}}.{{function_name}}(param);
window.{{app_name}}.{{function_name}}(param);

2. альтернатива - объект "окно"

добавить функцию {{function_name}} в окно объекта

function {{function_name}}(param) {}
->
window.{{function_name}} = function(param) {}

то вы можете вызвать свою функцию из браузера

{{function_name}}(param);
window.{{function_name}}(param);

--

может быть, я помогу кому-то

person BG BRUNO    schedule 22.01.2019

У вас есть несколько вариантов:

  1. Пусть плагин browserify-bridge автоматически экспортирует модули в сгенерированный модуль ввода. Это полезно для проектов SDK или ситуаций, когда вам не нужно вручную следить за тем, что экспортируется.

  2. Следуйте шаблону псевдопространства имен для свертывания:

Во-первых, упорядочите свою библиотеку следующим образом, воспользовавшись индексным поиском по папкам:

/src
--entry.js
--/helpers
--- index.js
--- someHelper.js
--/providers
--- index.js
--- someProvider.js
...

С помощью этого шаблона вы определяете запись следующим образом:

exports.Helpers = require('./helpers');
exports.Providers = require('./providers');
...

Обратите внимание, что требование автоматически загружает index.js из каждой соответствующей подпапки.

В своих подпапках вы можете просто включить аналогичный манифест доступных модулей в этом контексте:

exports.SomeHelper = require('./someHelper');

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

person deepelement    schedule 12.08.2015

Вы также можете вызвать свою функцию из html-файла следующим образом:

main.js: (будет в bundle.js)

window.onload = function () {
    document.getElementById('build-file')
        .addEventListener('click', buildFile)

}
function buildFile() {
 ...
}

индекс.html:

<button id="build-file"">Build file</button>
person live-love    schedule 30.12.2020

window.LogData =function(data){
   return unique(data);
};

Вызовите функцию просто LogData(data)

Это всего лишь небольшая модификация ответа thejh, но важная.

person Pratik Khadtale    schedule 01.05.2018
comment
Эта модификация не имеет отношения к проблемам автора вопроса и не добавляет никакой новой информации к уже существующим ответам. - person Galen Long; 05.05.2018

В целях отладки я добавил эту строку в свой code.js:

window.e = function(data) {eval(data);};

Тогда я мог запускать что угодно даже вне пакета.

e("anything();");
person Karveiani    schedule 23.07.2017