Browserify - Як викликати функцію, що входить до складу файлу, створеного за допомогою browserify у браузері


96

Я новачок у nodejs та browserify. Я почав із цього посилання .

У мене є файл 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 ??


Де ви хочете це зателефонувати? А чому ти хочеш це називати?
artur grzesiak

2
@arturgrzesiak: Я хочу використовувати цю функцію в одному з моїх інших проектів, який я буду запускати в браузері.
SharpCoder

Відповіді:


83

За замовчуванням browserify не дозволяє вам отримувати доступ до модулів поза кодом, який перевіряється, якщо ви хочете викликати код у модулі, який перевіряється, ви повинні переглядати свій код разом із модулем. Приклади цього див. На веб-сайті http://browserify.org/ .

Звичайно, ви також можете явно зробити свій метод доступним зовні:

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

Тоді ви могли зателефонувати LogData()з будь-якого місця на сторінці.


1
Дякую. Це працює. Чи означає це, що, створюючи функції замість вимовляти this.functionName, я повинен писати window.functionName? Чи є у нас ще якась робота для цього? Будь-які причини використання window.functionName?
SharpCoder

21
"ти повинен переглядати свій код разом із модулем" - Тьфу, а що, якщо я хочу зробити щось подібне onclick="someFunction()". Ви не можете сперечатися, що це рідкісний випадок використання!?!
BlueRaja - Danny Pflughoeft

57
У початківців серйозно не вистачає документації про те, як насправді використовувати Browserify на клієнті.
Олівер Діксон,

1
так, у документації повинно бути чітко зазначено, що цього дизайнерського рішення слід уникати, але передбачати чіткий шлях до його роботи, коли у вас немає альтернативи (у моєму випадку використання даних із шаблону для заповнення об’єкта JS) ... дякую @thejh за вказівку на просте рішення! ;)
Александр Мартіні

1
Я навіть не можу подумати про ситуацію, коли б ви НЕ хотіли робити свої основні функції доступними за межами модуля. Як це не поведінка за замовчуванням? Яка веб-програма не викликає функції?
Кібернетичний

101

Ключовою частиною поєднання окремих модулів з Browserify є --sопція. Він виставляє все, що ви експортуєте з вашого модуля, використовуючи вузли module.exportsяк глобальну змінну. Потім файл можна включити в <script>тег.

Це потрібно робити лише в тому випадку, якщо з якихось причин вам потрібна ця глобальна змінна. У моєму випадку клієнту потрібен був самостійний модуль, який можна було б включити на веб-сторінки, і їм не потрібно було турбуватися про цей бізнес Browserify.

Ось приклад, коли ми використовуємо --sопцію з аргументом module:

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

Це відкриє наш модуль як глобальну змінну з іменем module.
Джерело .

Оновлення: завдяки @fotinakis. Переконайтеся, що ви проїжджаєте --standalone your-module-name. Якщо ви забудете, що --standaloneприймає аргумент, Browserify може мовчки генерувати порожній модуль, оскільки не зможе його знайти.

Сподіваюся, це заощадить ваш час.


2
Я намагаюся переглянути браузерний код ES6. Але автономний об’єкт порожній, коли я намагаюся втілити його в браузері. Простий код ES6 без будь-яких модулів чудово працює в автономному режимі. Будь-які вказівки на це?
Джон

@jackyrudetsky не маю ідеї, я б рекомендував додати запитання щодо SO, це звучить як цікаве питання. може бути пов'язане з цим. github.com/substack/node-browserify/issues/1357
Матас Вайткевічус,

1
@fotinakis Це насправді було проблемою в Browserify github.com/substack/node-browserify/issues/1537
Джон

3
ІМО це має бути прийнятою відповіддю. Якщо ви використовуєте глобальну функцію, набагато краще мати власний простір імен, ніж вивішувати кожну функцію з вікна.
VictorB

1
@VictorB всі глобальні змінні в Javascript є елементами вікна, тому обидва методи досягають одного і того ж (додавання глобальних змінних до вікна)
Девід Лопес,

37

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

У вихідному скрипті, який потрібно об’єднати, обов’язково виставляйте функції, які потрібно викликати через module.exports. У скрипті клієнта ви можете викликати ці відкриті функції через <ім'я набору>. <Ім'я функції> . Ось приклад:

Мій вихідний файл src / script.js матиме таке:
module.exports = {myFunc: func};

Моя команда browserify виглядатиме приблизно так:
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>це не потрібно і не буде працювати.

Насправді, як і всі функції, що постачаються в браузері без автономного режиму, функція require не буде доступна поза вбудованим сценарієм . Browserify дозволяє використовувати деякі функції Node на стороні клієнта, але лише в самому пакетному сценарії ; це не призначено для створення автономного модуля, який ви можете імпортувати та використовувати де-небудь на стороні клієнта, саме тому нам доводиться йти на всі ці додаткові проблеми, щоб просто викликати одну функцію поза її пов’язаним контекстом.


3
Оце Так! Нарешті, практичний приклад.
N73k

1
Хороший приклад, але, оскільки "це забруднює глобальний простір імен, отже, не ідеально", не слід автоматично, це може бути прийнятним, якщо це лише одна функція; Просто дим і дзеркала, навіть myBundleприкріплюється до віконного об'єкта, window.myBundle.myFunc()а не до window.myFunc ()
joedotnot

1
Для людей, які наводять наскрізні приклади, мають бути додаткові бали.
Шаруд

Саме так слід писати документацію
Ellery Leung,

8

Я просто прочитав відповіді і, здається, ніхто не згадував про використання глобальної змінної сфери? Що корисно, якщо ви хочете використовувати той самий код у node.js та у браузері.

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

Тоді ви можете отримати доступ до TestClass де завгодно.

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

Примітка: Потім TestClass стає доступним скрізь. Що те саме, що використання змінної вікна.

Крім того, ви можете створити декоратор, який виставляє клас до глобального масштабу. Що дійсно приємно, але ускладнює відстеження, де визначена змінна.


Як ви самі говорите, додавання функції globalстворює той самий ефект, що і додавання до window, який вже був охоплений jjh. Ця відповідь не додає нової інформації.
Гален Лонг

@GalenLong, можливо, ти забув, що у node.js немає змінної вікна? А деякі бібліотеки, націлені на вузол та браузер, можуть замість цього використовувати глобальну. Моя відповідь отримала кілька голосів за, і поки що не в мінусі, тому я думаю, що вона інформативна для інших, якби не для вас.
DDD

Ти маєш рацію, @Azarus. На сторінці було ще дві повторювані відповіді, і я неправильно включив вашу до групи. Мої вибачення.
Гален Лонг

просто хочу зазначити, що вивішування парен тут є дуже поганою практикою для javascript, наприклад: застосуйте цей шаблон до ключового слова return і підготуйтеся до плачу. наприклад, return {}але опустіть фігурну дужку, що відкривається, до наступного рядка.
Sgnl

1
@Azarus Я створив скрипку, щоб продемонструвати, що я маю на увазі - jsfiddle.net/cubaksot/1
Sgnl

6

Прочитайте README.md про browserify про --standaloneпараметр або google "browserify umd"


19
Це більше натяк на те, де знайти відповідь, ніж відповідь.
user2314737

це призвело мене до рішення, яке я шукав протягом двох днів (як використовувати браузер для виводу з середовища require.js). Дякую!
Фліон

2

Щоб ваша функція була доступна як з 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

2

Мінімальний приклад для запуску

Це в основному те саме, що: 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.


1
exports.myfunc.= myfuncЧастина цього абсолютно необхідно і пропустили в інших відповідях.
parttimeturtle

2

це дуже просто - вся ця концепція стосується упаковки

1. альтернатива - об'єкт "це"

для цього я припускаю, що у вас є "лише 1 сценарій для цілої програми {{app_name}}" та "1 функція {{function_name}}"

додати функцію {{function_name}} до об’єкта "це"

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

тоді вам потрібно назвати цей об'єкт доступним - ви зробите це, додавши параметр "автономно з ім'ям", як іншим радять

так що якщо ви використовуєте "watchify" з "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);

-

можливо, я комусь допомагаю


1

У вас є кілька варіантів:

  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');
...

Зверніть увагу, що require автоматично завантажує index.js з кожної відповідної підпапки

У своїх підкаталогах ви можете просто включити подібний маніфест доступних модулів у цьому контексті:

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

Цей шаблон дуже добре масштабується і дозволяє контекстуально (папку за папкою) відстежувати те, що включити до згорнутого API.


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

Викличте функцію просто LogData(data)

Це лише невелика модифікація thejh в відповідь , але важливий один


Ця модифікація не має відношення до питань, що задають питання, і не додає жодної нової інформації, враховуючи вже існуючі відповіді.
Гален Лонг

-2

Для налагодження я додав цей рядок до свого code.js:

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

Тоді я міг запустити що завгодно, навіть поза пучком.

e("anything();");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.