2012-01-29 43 views
15

Tôi đang xây dựng tiện ích mở rộng của Chrome để thêm một số bài viết JavaScript vào Wikipedia. Theo như tôi biết, cách duy nhất để sử dụng RequireJS là thêm dòngRequireJS trong tiện ích mở rộng của Chrome

<script data-main="scripts/bla" src="scripts/require-jquery.js> 

Tuy nhiên, trong tiện ích mở rộng của Chrome, tôi không có quyền truy cập vào HTML để thêm dòng này. Bất kỳ đề xuất?

+0

Ông có thể làm rõ rằng hơn một chút? Cách bạn thường bao gồm các mô-đun với require.js sẽ thông qua javascript, không phải là thẻ tập lệnh: yêu cầu (["some/module", "a.js", "b.js"]); – Julian

+0

Tôi biết cách bao gồm các mô-đun, nhưng làm cách nào để tự bao gồm requireJS * sau khi tải trang và chỉ sử dụng JavaScript? – Randomblue

+0

Đây không phải là một câu trả lời thực sự cho câu hỏi của bạn, nhưng bạn có thể sử dụng chỉ cần tạo một kịch bản Greasemonkey và thực hiện tất cả các mã javascript của bạn [http://greasemonkey.mozdev.org/authoring.html](http://greasemonkey.mozdev .org/authoring.html) – tyranitar

Trả lời

17

Bạn có quyền truy cập vào DOM của trang từ Tiện ích mở rộng của Chrome qua content script, tuy nhiên tập lệnh nội dung sẽ chỉ có quyền truy cập vào các đối tượng JavaScript được tạo bởi chính số content script.

Có nhiều cách để bao gồm tập lệnh từ tiện ích mở rộng của Chrome, cách bạn đưa mã vào sẽ dựa trên những gì bạn định làm với nó.

Nếu bạn muốn nó trong trang popup của browser hoặc page action bạn có thể bao gồm nó từ tệp kê khai dưới dạng tập lệnh nội dung hoặc tham chiếu nó bằng cách sử dụng thẻ tập lệnh trong popup.html từ tài nguyên tương đối trong plugin của bạn.

Từ manifest:

{ 
    "name": "My extension", 
    ... 
    "content_scripts": [ 
    { 
     "matches": ["http://www.google.com/*"], 
     "css": ["mystyles.css"], 
     "js": ["jquery.js", "myscript.js"] 
    } 
    ], 
    ... 
} 

Từ popup.html:

<script data-main="scripts/bla" src="scripts/require-jquery.js> 

Nếu bạn muốn nó trong background page bạn có thể tham khảo nó từ trang nền sử dụng một thẻ script từ một nguồn lực tương đối trong plugin của bạn.

Từ background.html

<script data-main="scripts/bla" src="scripts/require-jquery.js> 

Nếu bạn muốn nó được đưa vào trang trình duyệt riêng của mình thì bạn cần phải sử dụng tiêm kịch bản động trên DOM của trang. Bạn có quyền truy cập vào DOM của trang từ một số content script. Xin lưu ý rằng nếu bạn tải JavaScript bằng cách sử dụng kỹ thuật này, bạn plugin JavaScript (từ trang nền, tập lệnh nội dung hoặc tập lệnh bật lên) sẽ không có quyền truy cập vào nó.

Bạn có thể tải requirejs từ tiện ích của mình bằng cách sử dụng phương thức chrome.extension.getURL hoặc từ vị trí được lưu trữ trên internet.

var script = document.createElement('script'); 
script.setAttribute("type", "text/javascript"); 
script.setAttribute("async", true); 
script.setAttribute("src", chrome.extension.getURL("require-jquery.js")); 
//Assuming your host supports both http and https 
var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement; 
head.insertBefore(script, head.firstChild) 
+0

Tôi có một tập lệnh nội dung mà cách thông thường để bao gồm nó là sử dụng thẻ 'script' có' dữ liệu chính 'thuộc tính. Làm cách nào tôi có thể chỉ định thuộc tính 'data-main' bên trong tệp kê khai? – Randomblue

+0

Không, không có cách nào để thêm thẻ thuộc tính vào tập lệnh nội dung nếu bạn bao gồm nó từ tệp kê khai. Bạn có thể thử sử dụng tính năng tiêm có lập trình: http://code.google.com/chrome/extensions/content_scripts.html#pi –

+1

Thực tế, việc lập trình tiêm sẽ không hoạt động, cùng một vấn đề (sẽ không cho phép các thuộc tính trên thẻ tập lệnh). Tôi khuyên bạn nên thay vì sử dụng RequireJS bạn sử dụng AMD với Almond.js: https://github.com/jrburke/almond - hãy chắc chắn sử dụng trình tối ưu hóa requireJS đầu tiên như r.js: https://github.com/jrburke/ r.js –

15

đây là cách bạn có thể thực hiện trong trang nền.

Trong file manifest:

"background": { 
    "scripts": [ "scripts/require.js","scripts/main.js"] 
    }, 

Trong main.js:

require.config({ 
     baseUrl: "scripts" 
    }); 

    require([ /*...*/ ], function( /*...*/) { 
     /*...*/ 

    }); 

Thay vì điều này:

<script data-main="scripts/bla" src="scripts/require.js> </script> 

Bạn sẽ sử dụng này:

<script src="scripts/require-jquery.js ></script> 
<script src="scripts/main.js > </script> 

See this question: Using Require.js without data-main

Bạn cũng có thể làm điều đó trong trang nội dung bằng ý tưởng này.

Câu hỏi hay bằng cách này.Tôi thích câu trả lời là Adam Ayres's.

+0

Đây phải là câu trả lời được chấp nhận vì nó thực sự giải quyết câu hỏi. Cũng lưu ý rằng nếu bạn sử dụng một plugin RequireJS như jsx, bạn có thể cần phải thêm '" content_security_policy ":" script-src 'self' 'unsafe-eval'; object-src 'self' "' vào 'manifest. tệp json' để Chrome cho phép tiện ích mở rộng sử dụng 'eval()'. Điều này có thể bị xóa trong bản phát hành sản phẩm nếu bạn sử dụng r.js để nhóm mọi thứ lại với nhau. – jdunning

1

Để sử dụng nó trong một kịch bản nội dung bạn chỉ có thể bao gồm nó trong manifest.json như bạn đầu tiên phụ thuộc:

{ 
    "name": "My extension", 
    ... 
    "content_scripts": [ 
    { 
     "matches": ["http://www.google.com/*"], 
     "css": ["mystyles.css"], 
     "js": ["requirejs.js", "myscript.js"] 
    } 
    ], 
    ... 
} 

Nó sẽ KHÔNG gây ô nhiễm không gian tên toàn cầu (cửa sổ) để không phải lo lắng về điều đó; chỉ có sẵn cho các tập lệnh mở rộng. Cũng trong manifest.json bạn phải đặt tên cho các tệp mà requirejs có thể sử dụng bằng cách đặt tên chúng là "web_accessible_resources", để làm cho việc này dễ dàng đặt tất cả chúng vào một thư mục (ví dụ: js /) để bạn có thể sử dụng wildcard:

{ 
    "name": "My extension", 
    ... 
    "web_accessible_resources": [ 
    "js/*" 
    ], 
    ... 
} 

Và sau đó trong kịch bản của bạn (ví dụ myscript.js) để sử dụng requirejs chỉ yêu cầu các phụ thuộc sử dụng chrome.extension.getURL, như thế này:

requirejs([chrome.extension.getURL('js/library')], function(library) { 
    ... 
} 
+0

Khi tôi sử dụng phương pháp này, tôi có thể tải các mô-đun bổ sung của mình một cách chính xác, nhưng sau đó tôi nhận được thông báo lỗi, 'Tham chiếu không bắt buộc: xác định không được định nghĩa'. Điều đó có ý nghĩa gì, bạn có thể làm việc này không? –

2

EDIT dưới đây vẫn còn đúng cho vani đồng bằng yêu cầu .js, nhưng tìm thấy cách giải quyết bằng cách yêu cầu RequireJS

Github: https://github.com/jeroendelau/requirejs
Bower: Chòi chơi cho cài đặt requirejs-cho plug-in mở rộng

orignal POST

Tiêm nó thành kịch bản nội dung đến nay là khó khăn nhất. Và các câu trả lời ở trên không đầy đủ hoặc không chính xác.

Bối cảnh và Popup:
Go với câu trả lời trước đó của @nafis, họ sẽ làm việc

Content Script
Đây là một trong rất khôn lanh, và phần này từ api description là chìa khóa:

Execution environment
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.

Cách trực quan này phải chính xác
manifest.json

{ 
    "name": "My extension", 
    ... 
    "content_scripts": [ 
    { 
     "matches": ["http://www.google.com/*"], 
     "css": ["mystyles.css"], 
     "js": ["requirejs.js", "myscript.js"] 
    } 
    ], 
    ... 
    "web_accessible_resources": [ 
    "js/*" 
    ], 
... 
} 

myscript.js

require(["myFancyModule"], function (FM) { 
    ... 
}); 

này sẽ không hoạt

Vấn đề là requirejs sẽ tiến hành tải tất cả phụ thuộc của bạn bằng cách tiêm <script> thẻ trong tiêu đề. Các thẻ tập lệnh này được thực hiện trong môi trường PAGE, không phải trong môi trường EXTENSION đặc biệt. Và điều này quan trọng.

  1. Dependencies không tải từ requirejs không được tải trong trang môi trường
  2. Nếu chủ sở hữu trang web đã alreay thêm requirejs, nó migh xung đột
  3. Bạn có thể quyết định tiêm require.js vào trang, như @Adam gợi ý, nhưng trong trường hợp đó, không có tính năng tiện ích mở rộng nào của bạn sẽ hoạt động.lưu trữ, nhắn tin, yêu cầu qua nhiều trang web không phải là có sẵn

Vì vậy, để những người làm việc, các mô-đun được tải bởi requirejs cần phải được đưa vào môi trường tiện ích mở rộng. Có thể sử dụng plugin requirejs để thay đổi hành vi tải.

Do cách làm việc này là giải pháp rất thanh nha, VÀ nó ngăn cản bạn từ khi nhìn thấy các script trong trình gỡ lỗi dưới kịch bản. Nhưng nếu bạn tuyệt vọng, nó sẽ hoạt động.

myscript.js

/** 
* Inject the plugin straight into requirejs 
*/ 
define("Injector", { 
    load: function (name, req, onload, config) { 

    //Load the script using XHR, from background 
    var oReq = new XMLHttpRequest(); 
    oReq.addEventListener("load", function() { 

     //Find depenencies in the script, and prepend the 
     //Injector! plugin, forcing the load to go through this 
     //plugin. 
     var modified = getDeps(oReq.response) 

     //have requirejs load the module from text 
     //it will evaluate the define, and process dependencies 
     onload.fromText(modified); 
    }); 
    oReq.open("GET", req.toUrl(name) + ".js"); 
    oReq.send(); 

    //Find dependencies and prepend Injector! 
    function getDeps(script) 
    { 
     //extract the define call, reduced to a single line 
     var defineCall = script.match(/define([\s\S])*?{/m)[0].split("\n").join(""); 
     //extract dependenceis from the call 
     var depsMatch = defineCall.match(/\[([\s\S]*?)\]/); 

     //if there are dependencies, inject the injectors 
     if (depsMatch) 
     { 
     var deps = depsMatch[0]; 
     var replaced = deps.replace(/(\'|\")([\s\S]*?)\1/g, '$1Injector!$2$1'); 
     return script.replace(/define([\s\S]*?)\[[\s\S]*?\]/m, 'define$1' + replaced); 
     } 
     //no dependencies, return script 
     return script; 
    } 
    } 
}); 

/** 
* Call all your dependencies using the plugin 
*/ 
require(["Injector!myFancyModule"], function (FM) { 
     chrome.storage.local.get({something}); 
}); 
Các vấn đề liên quan