使用浏览器化的 JS 库 Angular 2

Using a browserified JS library with Angular 2

我想在我的 Angular 2 项目中使用 libquassel (https://github.com/magne4000/node-libquassel)。该库是浏览器化的,所以理论上它应该可以工作,但我不确定如何将它导入我的项目。

我尝试添加到我的 typings.d.ts

declare module 'libquassel';

然后使用

导入库
import * as Quassel from 'libquassel';

但我得到

EXCEPTION: net.Socket is not a function

当我尝试 运行 我的代码时,我认为这是另一个嵌入 client/libquassel.js 文件的 browserify 库。

如何使用这个库?

编辑:我会在这里回答所有问题:

然后将QuasselService添加到app.module.ts中的providers数组。 这将是我的问题的一个很好的演示,即如何在我的 QuasselService.

中导入 libquassel

Angular-cli使用webpack

您需要将 JS 文件添加到 angular-cli.json 文件中的 apps[0].scripts 中,然后 WebPack 会像加载标签一样进行捆绑。

apps:[
{
  ...
  "scripts": [
    "../node_modules/libquassel/client/libquassel.js"
  ],

如果这样做,您可以通过在 src/typings.d.ts 或组件中添加 declare var Quassel :any; 来实现。

let quassel = new Quassel("localhost", 4242, {}, function(next) {
  next("user", "password");
});
quassel.connect();

更新(修复它,这次是真的)

它在您的代码中不起作用有一个很好的理由:因为我对您撒了谎。如果您还没有 "diffed" ,那么这是我真正的作弊方法。

我仍然需要 require libquassel 2 次,但第一次不是通过调用 require 完成的,这是无用的,而是通过将它添加到 angular-cli.jsonscripts 部分:

  "scripts": [
    "../node_modules/libquassel/client/libquassel.js"
  ],

这很重要,因为 "client/libquassel.js" 声明了它自己的 require 但没有明确导出它,所以如果您这样做

require('libquassel/client/libquassel.js');

libquassel 的自定义 require 卡在匿名命名空间中,您无法访问它。另一方面,将它添加到 scripts 部分,让 libquassel.js 用它的 require 污染全局命名空间(即 window),从而使其工作。

因此,使其工作的实际步骤是:

  1. 将 client/libquassel.js 添加到 angular-cli.json
  2. 的脚本 section
  3. 使用额外的 require 实际加载 Quassel 模块
let Quassel = window['require']('quassel'); // note that usingg require('quassel') leads to compilation error
let quasselObj = new Quassel(...);

这是我的尝试。看起来你需要 require "quassel" 2 次:第一次从 "../node_modules/libquassel/client/libquassel.js" 加载 JS,第二次到让来自那个 JS 的覆盖 require 实际上解析 "quassel"。在 'main.ts':

中,这是一个似乎对我有用的技巧
require('../node_modules/libquassel/client/libquassel.js');
let Quassel = window['require']('quassel'); // note that using require('quassel') leads to compilation error
let quasselObj = new Quassel(...);

我还需要一个技巧来避免因编译错误而失败:特别是我必须使用 window['require'] 而不是仅 require 进行第二次调用,因为它是对内部 [= client/libquassel.js 中定义的 16=] 和 Node/Angular-cli 单独无法处理它。

请注意,在该设置之后,我的应用程序仍然因某些 AJAX 中的运行时错误而失败,因为浏览 libquassel.js 似乎需要在服务器端 URL 处设置代理像 /api/vm/net/connect,这可能是 net-browsify 的服务器端应该做的,但我没有尝试设置它。

回复评论

看起来您使用的是旧版本的 Angular-CLI,如果您升级,一切都应该可以正常工作。

这是 ng --version 在我原来的机器上告诉我的

angular-cli: 1.0.0-beta.28.3
node: 6.10.0
os: win32 x64
@angular/common: 2.4.10
@angular/compiler: 2.4.10
@angular/core: 2.4.10
@angular/forms: 2.4.10
@angular/http: 2.4.10
@angular/platform-browser: 2.4.10
@angular/platform-browser-dynamic: 2.4.10
@angular/router: 3.4.10
@angular/compiler-cli: 2.4.10

当我试图将我的原始项目复制到另一台机器时,我也遇到了关于 require 的编译错误,但是当我将 Angular-CLI 更新为

@angular/cli: 1.0.0
node: 6.10.0
os: darwin x64
@angular/common: 2.4.10
@angular/compiler: 2.4.10
@angular/core: 2.4.10
@angular/forms: 2.4.10
@angular/http: 2.4.10
@angular/platform-browser: 2.4.10
@angular/platform-browser-dynamic: 2.4.10
@angular/router: 3.4.10
@angular/cli: 1.0.0
@angular/compiler-cli: 2.4.10

它编译和工作相同。我所做的只是按照说明

The package "angular-cli" has been deprecated and renamed to "@angular/cli".

Please take the following steps to avoid issues:
"npm uninstall --save-dev angular-cli"
"npm install --save-dev @angular/cli@latest"

然后按照 ng serve

的说明更新了 angular-cli.json

工作起来很有魅力:

declare var require;
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );

查看node_module中libquassel的文件夹,发现根目录下没有index.js

当没有 index.js 时,你不能 这样做:

 require( 'libquassel' );

仅仅是因为 node 不知道要为您提供什么,所以您需要指定确切的路径,在这种情况下这还不错。

此外,请注意,最好将 declare var require; 移动到位于 src 文件夹下的 typings 文件,因为您可能需要再次声明它,所以最好放在那儿。

编辑: 这是我在尝试像下面这样实例化 Quassel 之后发现的:

const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
var quassel = new Quassel( "quassel.domain.tld",
    4242,
    { backloglimit : 10 },
    function ( next ) {
        next( "user", "password" );
    } );
console.log( 'quassel', quassel );

这是我的控制台日志:

但是话虽如此,我意识到 libquassel.js 内部存在问题,如下所示:

在第 10 行,他们这样做:

   var net = require('net');

看看他们的 package.json,没有 net 这样的东西,有 net-browserify-alt;

因此,如果他们将该导入更改为:

 var net = require('net-browserify-alt'),

一切正常。

话虽如此,显然你不想编辑你的 node_module,但我真的很惊讶这甚至在 angular 和 webpack 之外是如何工作的,因为很明显他们'我提到了一个错误的 node_module 如果你 google ,只有一个名为 net 的包,我看了一下它是空的和虚拟的 !!!!

** ********** 更新:********* **

具体需要做什么:

1- 运行 ng eject

这将在您的根目录中生成一个 webpack.conf.js

2- 在里面找到 resolve 属性 并添加:

 "alias":{
     'net':'net-browserify-alt'
  },

所以你的决心可能看起来像:

"resolve": {
    "extensions": [
      ".ts",
      ".js"
    ],
      "alias":{
         'net':'net-browserify-alt'
      },
    "modules": [
      "./node_modules"
    ]
  },

3- 导入并使用它:

declare var require;
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
var quassel = new Quassel( "quassel.domain.tld",
    4242,
    { backloglimit : 10 },
    function ( next ) {
        next( "user", "password" );
    } );
console.log( 'quassel', quassel );

注意:

查看 webpack 配置,似乎 webpack 喜欢覆盖几个模块:

"node": {
    "fs": "empty",
    "global": true,
    "crypto": "empty",
    "tls": "empty",
    "net": "empty",
    "process": true,
    "module": false,
    "clearImmediate": false,
    "setImmediate": false
  }

我不完全知道为什么,但这个列表在 webpack 配置中,似乎使 net 变得不安全(空),这就是我们必须创建别名的原因。

关键问题是浏览器化 libquassel 库中包含一个全局 require 函数。这与标准 require 函数冲突。

有很多方法可以处理这个问题,但一种解决方案是将 /libquassel/client/libquassel.js(和缩小版本)复制到您的 /src/app/ 目录。

然后 运行 在这些文件中进行搜索和替换,将所有出现的 require 更改为 _quasselRequire_

您可以为 libquassel.jslibquassel.min.js 执行此操作。

要利用它,您可以在 quassel.service.ts:

中执行类似的操作
import { Injectable } from '@angular/core';
import * as dummyQuassel1 from './libquassel.js'

var dummyQuassel2 = dummyQuassel1; // something just to force the import

declare var _quasselRequire_ :any;

@Injectable()
export class QuasselService {

  constructor() { 

    // set up in the constructor as a demo

    let Quassel = _quasselRequire_( 'quassel' );
    console.log('Quassel', Quassel);

    var quassel = new Quassel( 
        "quassel.domain.tld",
        4242,
        { backloglimit : 10 },
        function ( next ) {
            next( "user", "password" );
        } 
    );

    console.log('quassel', quassel);

    quassel.on('network.init', function(networkId) {
        console.log("before net");
        var network = quassel.getNetworks().get(networkId);
        console.log("after net");
        // ...
    });

    console.log("before connect");
    quassel.connect();  
    console.log("after connect");
  }

  getQuassel() {
      return 'My Quassel service';
  }
}

这本身会导致错误:

POST http://localhost:4200/api/vm/net/connect 404 (Not Found)

Error: Uncaught, unspecified 'error' event. at new Error (native) at Quassel.n.emit (http://localhost:4200/main.bundle.js:570:4210) [angular] at Socket. (http://localhost:4200/main.bundle.js:810:19931) [angular] at Socket.EventEmitter.emit (http://localhost:4200/main.bundle.js:573:1079) [angular] ...

但据我所知,这是相当正常的,因为我还没有设置 Express 等。

注意:名称 _quasselRequire_ 可以是任何适合您的名称。