Browserify - Cách gọi hàm được đóng gói trong tệp được tạo thông qua Browserify trong trình duyệt


95

Tôi chưa quen với nodejs và đã duyệt qua. Tôi bắt đầu với liên kết này .

Tôi có tệp main.js chứa mã này

var unique = require('uniq');

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

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

Bây giờ tôi Cài đặt mô-đun uniq với npm:

 npm install uniq

Sau đó, tôi gói tất cả các mô-đun bắt buộc bắt đầu từ main.js thành một tệp duy nhất có tên là pack.js bằng lệnh Browserify:

browserify main.js -o bundle.js

Tệp được tạo trông giống như sau:

(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])

Sau khi bao gồm tệp Bundle.js vào trang index.htm của tôi, làm cách nào để gọi hàm logData ??


Bạn muốn gọi nó ở đâu? Và tại sao bạn muốn gọi nó?
artur grzesiak

2
@arturgrzesiak: Tôi muốn sử dụng chức năng này trong một trong những dự án khác của tôi mà tôi sẽ chạy trong trình duyệt.
SharpCoder

Câu trả lời:


80

Theo mặc định, Browserify không cho phép bạn truy cập vào các mô-đun từ bên ngoài mã đã được duyệt - nếu bạn muốn gọi mã trong một mô-đun đã được duyệt, bạn phải duyệt mã của mình cùng với mô-đun. Xem http://browserify.org/ để biết các ví dụ về điều đó.

Tất nhiên, bạn cũng có thể làm cho phương thức của mình có thể truy cập từ bên ngoài một cách rõ ràng như sau:

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

Sau đó, bạn có thể gọi LogData()từ bất kỳ nơi nào khác trên trang.


1
Cảm ơn bạn. Những công việc này. Điều này có nghĩa là, trong khi tạo các hàm thay vì nói this. Chức năngName, tôi nên viết window. Chức năngName? Chúng ta có bất kỳ công việc nào khác cho việc này không? Bất kỳ lý do nào để sử dụng window. Chức năngName?
SharpCoder

19
"bạn phải duyệt mã của mình cùng với mô-đun" - Ugh, nếu tôi muốn làm điều gì đó giống như vậy onclick="someFunction()". Bạn không thể tranh cãi rằng đó là một trường hợp sử dụng hiếm gặp!?!
BlueRaja - Danny Pflughoeft

55
Thiếu nghiêm trọng tài liệu dành cho người mới bắt đầu về cách thực sự sử dụng Browserify trên máy khách.
Oliver Dixon

1
vâng, tài liệu phải nêu rõ rằng đây là một quyết định thiết kế nên tránh, nhưng hãy cung cấp một đường dẫn rõ ràng để làm cho nó hoạt động khi bạn không có giải pháp thay thế (trong trường hợp của tôi, sử dụng dữ liệu từ mẫu để điền đối tượng JS) ... cảm ơn @thejh đã chỉ ra một giải pháp đơn giản! ;)
Alexandre Martini

1
Tôi thậm chí không thể nghĩ đến tình huống mà bạn KHÔNG muốn cung cấp các chức năng chính của mình bên ngoài mô-đun. Làm thế nào đây không phải là hành vi mặc định? Loại ứng dụng web nào không gọi các chức năng?
Điện tử

100

Phần quan trọng của việc đóng gói các mô-đun độc lập với Browserify là --stùy chọn. Nó hiển thị bất cứ thứ gì bạn xuất từ ​​mô-đun của mình bằng cách sử dụng nút module.exportslàm biến toàn cục. Sau đó, tệp có thể được đưa vào<script> thẻ.

Bạn chỉ cần làm điều này nếu vì lý do nào đó bạn cần biến toàn cục đó được hiển thị. Trong trường hợp của tôi, khách hàng cần một mô-đun độc lập có thể được đưa vào các trang web mà họ không cần phải lo lắng về công việc Browserify này.

Đây là một ví dụ mà chúng tôi sử dụng --stùy chọn với đối số là module:

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

Điều này sẽ hiển thị mô-đun của chúng tôi dưới dạng một biến toàn cục được đặt tên module.
Nguồn .

Cập nhật: Cảm ơn @fotinakis. Hãy chắc chắn rằng bạn đang vượt qua --standalone your-module-name. Nếu bạn quên điều đó--standalone có một đối số, Browserify có thể âm thầm tạo một mô-đun trống vì nó không thể tìm thấy nó.

Hy vọng điều này giúp bạn tiết kiệm thời gian.


2
Tôi đang cố gắng duyệt mã ES6 đã được rút gọn. Nhưng đối tượng độc lập trống khi tôi cố gắng điều khiển nó trong trình duyệt. Mã ES6 đơn giản không có bất kỳ mô-đun nào hoạt động tốt ở chế độ độc lập. Bất kỳ gợi ý về điều này?
John

@jackyrudetsky không có ý kiến, tôi khuyên bạn nên thêm một câu hỏi trên SO, nghe có vẻ là một vấn đề thú vị. có thể liên quan đến điều này. github.com/substack/node-browserify/issues/1357
Matas Vaitkevicius

1
@fotinakis Đây thực sự là một vấn đề trong Browserify github.com/substack/node-browserify/issues/1537
John

3
IMO đây phải là câu trả lời được chấp nhận. Nếu bạn đang sử dụng một hàm toàn cục, thì tốt hơn nhiều nên có không gian tên riêng của bạn hơn là treo mọi hàm trên cửa sổ.
VictorB

1
@VictorB tất cả các biến toàn cầu trong Javascript là những yếu tố của cửa sổ, vì vậy cả hai phương pháp đạt được điều tương (thêm các biến toàn cầu để cửa sổ)
David Lopez

37

Câu trả lời của @Matas Vaitkevicius với tùy chọn độc lập của Browserify là đúng ( câu trả lời của @ thejh bằng cách sử dụng biến window global cũng hoạt động, nhưng như những người khác đã lưu ý, nó gây ô nhiễm không gian tên chung nên không lý tưởng). Tôi muốn thêm một chút chi tiết về cách sử dụng tùy chọn độc lập.

Trong tập lệnh nguồn mà bạn muốn đóng gói, hãy đảm bảo hiển thị các chức năng bạn muốn gọi qua module.exports. Trong tập lệnh máy khách, bạn có thể gọi các hàm được tiếp xúc này qua <bundle-name>. <func-name> . Đây là một ví dụ:

My nguồn tập tin src / script.js sẽ có điều này:
module.exports = {myFunc: func};

Lệnh Browserify của tôi sẽ trông giống như sau:
browserify src/script.js --standalone myBundle > dist/bundle.js

tập lệnh ứng dụng khách dist / client.js của tôi sẽ tải tập lệnh đi kèm
<script src="bundle.js"></script>
và sau đó gọi hàm tiếp xúc như sau:
<script>myBundle.myFunc();</script>


Không cần yêu cầu tên gói trong tập lệnh ứng dụng khách trước khi gọi các hàm được tiếp xúc, ví dụ: <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script>không cần thiết và sẽ không hoạt động.

Trên thực tế, cũng giống như tất cả các hàm được duyệt qua gói mà không có chế độ độc lập, hàm yêu cầu sẽ không khả dụng bên ngoài tập lệnh được đóng gói . Browserify cho phép bạn sử dụng một số hàm Node phía máy khách, nhưng chỉ trong chính tập lệnh đi kèm ; nó không có nghĩa là để tạo một mô-đun độc lập mà bạn có thể nhập và sử dụng ở bất kỳ đâu phía máy khách, đó là lý do tại sao chúng ta phải gặp thêm rắc rối này chỉ để gọi một hàm duy nhất bên ngoài ngữ cảnh đi kèm của nó.


3
Chà! Cuối cùng là một ví dụ thực tế.
N73k

1
Ví dụ tốt, nhưng theo như "nó gây ô nhiễm không gian tên chung do đó không lý tưởng" không tự động tuân theo, nó có thể được chấp nhận nếu nó chỉ có một chức năng; Chỉ cần hút thuốc và gương, thậm chí myBundlebị gắn liền với đối tượng cửa sổ, window.myBundle.myFunc()thay vì window.myFunc ()
joedotnot

1
Nên có thêm điểm cho những người đưa ra các ví dụ từ đầu đến cuối.
Sharud

Đó là cách tài liệu nên được viết
Ellery Leung

7

Tôi chỉ đọc qua các câu trả lời và có vẻ như không ai đề cập đến việc sử dụng phạm vi biến toàn cục? Sẽ hữu ích nếu bạn muốn sử dụng cùng một mã trong node.js và trong trình duyệt.

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

Sau đó, bạn có thể truy cập TestClass ở bất kỳ đâu.

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

Lưu ý: Sau đó, TestClass sẽ có sẵn ở mọi nơi. Điều này cũng giống như việc sử dụng biến cửa sổ.

Ngoài ra, bạn có thể tạo trình trang trí hiển thị một lớp cho phạm vi toàn cầu. Điều này thực sự tốt nhưng làm cho nó khó theo dõi nơi một biến được xác định.


Như bản thân bạn nói, việc thêm hàm để globaltạo ra hiệu ứng tương tự như thêm vào window, cái đã được đề cập trong cái jh. Câu trả lời này không có thêm thông tin mới.
Galen Long

@GalenLong Có thể bạn quên rằng không có biến cửa sổ trong node.js? Và một số thư viện nhắm mục tiêu nút và trình duyệt có thể muốn sử dụng toàn cầu thay thế. Câu trả lời của tôi đã nhận được một số lượt ủng hộ và vẫn chưa bị trừ đi vì vậy tôi nghĩ rằng nó có nhiều thông tin cho những người khác nếu không dành cho bạn.
DDD

Bạn nói đúng, @Azarus. Có hai câu trả lời trùng lặp khác trên trang và tôi đã đưa sai câu trả lời của bạn vào trong nhóm. Lời xin lỗi của tôi.
Galen Long

chỉ muốn lưu ý rằng các parens treo ở đây là một thực hành rất tệ cho javascript, ví dụ: áp dụng mẫu này cho từ khóa return và chuẩn bị khóc. ví dụ return {}nhưng bỏ dấu ngoặc nhọn mở đầu xuống dòng tiếp theo.
Sgnl 29/09/18

1
@Azarus Tôi đã tạo một trò chơi điện tử để chứng minh ý tôi - jsfiddle.net/cubaksot/1
Sgnl 14/01/19

6

Đọc README.md của Browserify về --standalonetham số hoặc google "Browserify umd"


19
Đây là một gợi ý về nơi để tìm câu trả lời hơn là một câu trả lời.
user2314737

điều này dẫn tôi đến giải pháp mà tôi đã tìm kiếm trong hai ngày (cách sử dụng đầu ra Browserify từ môi trường request.js). cảm ơn bạn!
Flion

2

Để cung cấp chức năng của bạn từ cả HTML và từ nút phía máy chủ:

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>

Chạy:

npm install uniq
browserify main.js > bundle.js

và bạn sẽ nhận được kết quả tương tự khi mở main.html trong trình duyệt như khi chạy

node main.js

2

Ví dụ tối thiểu có thể chạy được

Điều này về cơ bản giống như: https://stackoverflow.com/a/43215928/895245 nhưng với các tệp cụ thể sẽ cho phép bạn chỉ chạy và dễ dàng tự tái tạo.

Mã này cũng có sẵn tại: 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>

Cách sử dụng Node.js:

#!/usr/bin/env node

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

console.log(browserify_hello_world.myfunc());

Tạo out.jsđể sử dụng trình duyệt:

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

Cả trình duyệt và dòng lệnh đều hiển thị đầu ra mong đợi:

1 2 3

Đã thử nghiệm với Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.


1
Các exports.myfunc.= myfuncphần của điều này là cực kỳ quan trọng và bỏ lỡ trong câu trả lời khác.
parttimeturtle

1

Bạn có một vài lựa chọn:

  1. Cho phép plugin Browserify-bridge tự động xuất mô-đun sang mô-đun mục nhập đã tạo. Điều này hữu ích cho các dự án SDK hoặc các tình huống mà bạn không phải cập nhật những gì được xuất theo cách thủ công.

  2. Làm theo mẫu không gian tên giả để hiển thị cuộn lên:

Đầu tiên, hãy sắp xếp thư viện của bạn như thế này, tận dụng việc tra cứu chỉ mục trên các thư mục:

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

Với mẫu này, bạn xác định mục nhập như sau:

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

Lưu ý rằng yêu cầu tự động tải index.js từ mỗi thư mục con tương ứng

Trong các thư mục con của bạn, bạn chỉ có thể bao gồm một tệp kê khai tương tự của các mô-đun có sẵn trong ngữ cảnh đó:

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

Mô hình này chia tỷ lệ thực sự tốt và cho phép theo dõi theo ngữ cảnh (từng thư mục) về những gì cần đưa vào api cuộn lên.


1

nó thực sự đơn giản - toàn bộ khái niệm này là về gói

1. thay thế - đối tượng "this"

vì mục đích này, tôi sẽ giả sử bạn có "chỉ 1 tập lệnh cho toàn bộ ứng dụng {{app_name}}" và "1 chức năng {{function_name}}"

thêm hàm {{function_name}} vào đối tượng "this"

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

thì bạn phải đặt tên cho đối tượng đó để có sẵn - bạn sẽ làm điều đó thêm param "độc lập với tên" như những người khác đã khuyên

vì vậy nếu bạn sử dụng "watchify" với "Browserify", hãy sử dụng

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

hoặc dòng lệnh

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

thì bạn có thể gọi hàm của mình từ trình duyệt

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

2. thay thế - đối tượng "cửa sổ"

thêm hàm {{function_name}} vào đối tượng "cửa sổ"

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

thì bạn có thể gọi hàm của mình từ trình duyệt

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

-

có lẽ tôi giúp ai đó


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

Gọi hàm đơn giản bằng LogData(data)

Đây chỉ là một sửa đổi nhỏ cho câu trả lời của thejh nhưng quan trọng


Sửa đổi này không liên quan đến mối quan tâm của người đặt câu hỏi và không thêm bất kỳ thông tin mới nào với các câu trả lời đã có.
Galen Long

-2

Vì mục đích gỡ lỗi, tôi đã thêm dòng này vào code.js của mình:

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

Sau đó, tôi có thể chạy bất cứ thứ gì ngay cả bên ngoài gói.

e("anything();");
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.