3

整理下英文的方案吧.. 问题大致解决, 但没有详细测试过每种方案.

关于在 Popup 页面使用 RequireJS

我们在线上使用 RequireJS 时通过后端代码选择性对 <script> 标签进行渲染,
在 popup 页面无法用类似方案达成, 我暂时拟定方案是不进行代码合并,
转而使用 Uglify 的 Grunt 对每个文件单独进行混淆, 然后 zip 压缩..

在 Popup 里 HTML 当中不允许内嵌 JS 代码, 因此放在单独文件,
另外 Handlebars 因为没有编译, 会用到 eval 代码, 而扩展里是屏蔽的.
暂定在 content_security_policy 配置 unsafe-eval 允许模版执行..

实际上压缩还是有遇到问题的,RequireJS 依赖的 require exports modules 被替换了
解决方案就是在 [Uglify 里设定保留的标识符], 在插件里是 except 的配置:

options:
  mangle:
    except: [
      'require'
      'exports'
      'module'
    ]

Content Script 里遇到的问题

RequireJS 兼容简化的 CommonJS 语法, 代码执行前会主动分析依赖,
然后取模块的名称添加对应的 <script> 标签来对代码进行加载.
这里的问题是, 出现在 Content Script 时, 这个路径是对应当前页面的路径,
而正常运行代码需要是在 chrome-extension:// 路径下的代码.

网上的解决方案

搜到一个扩展中使用 RequireJS 的幻灯片, 中间提到了这个用法
代码在 GitHub 上可以查看, 内容是:

(function() {
  var global = this;
  require.load = function (context, moduleName, url) {
    var xhr;
    xhr = new XMLHttpRequest();
    xhr.open("GET", chrome.extension.getURL(url) + '?r=' + new Date().getTime(), true);
    xhr.onreadystatechange = function (e) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        eval.call(global, xhr.responseText + '\n//@ sourceURL=' + url);
        context.completeLoad(moduleName)
      }
    };
    xhr.send(null);
  };
})();

主要就是覆盖了原生加载方式, 获取了扩展的 url, 然后加载代码.
测试可用..

RequireJS 插件的问题

后来也注意到 RequireJS 的插件, 比如 json, text 的插件, 都没有搞定这事情.
打断点看了下, 发现是插件里的 load 方法存在问题,
按照文档.. 插件也是覆写几个方法的事情.., 于是开始手改了.

if (chrome && chrome.extension) {
  if (config.baseUrl[config.baseUrl.length - 1] == '/') {
    name = chrome.extension.getURL(config.baseUrl + name)
  } else {
    name = chrome.extension.getURL(config.baseUrl + '/' + name)
  }
}

目前基本运行成功, 没有形似进行测试.

其他

搜到 StackOverflow 和 Google Groups 时有提到个 Cajon 模块,
看介绍和 almond 类似是 RequireJS 的官方定制版本..
Cajon 支持 CMD 语法的加载... 据说可以用在扩展里...
具体没有深入, 有了解的同学麻烦留言告知啦.. :P

https://github.com/requirejs/cajon/


返回博客首页: http://blog.tiye.me


题叶
17.3k 声望2.6k 粉丝

Calcit 语言作者