使用带有Angular 2的浏览器化JS库

时间:2017-03-17 13:58:24

标签: javascript angular typescript browserify

我想在我的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文件的库。

我该如何使用这个库?

修改:我将在此回答所有问题:

  • 我的设置是一个简单的角度cli项目。没有花哨的东西,只有ng new proj1然后是npm install libquassel --save
  • 我的index.html没有其他任何ng new没有放在那里的内容。
  • 我尝试使用import * as Quassel from 'libquassel'var Quassel = require('quassel')(及其排列)导入库,但没有任何好运(错误从unknown function 'require'变为can't find module lib|quassel)。
  • 重新制作项目的步骤:

    ng new test
    cd test
    npm install libquassel --save
    ng g s quassel
    

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

4 个答案:

答案 0 :(得分:5)

更新(修复此问题,这次是真实的)

有一个很好的理由说明它在你的代码中不起作用:因为我欺骗了你。所以这是我真正的欺骗,以防你没有"差异"它自己呢。

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

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

这很重要,因为" client / libquassel.js"声明它自己的require但是如果你做

则不要明确地导出它
require('libquassel/client/libquassel.js');

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

所以实现它的实际步骤是:

  1. 将client / libquassel.js添加到section
  2. 的脚本angular-cli.json
  3. 使用其他require实际加载Quassel模块
  4. 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来进行第二次调用,因为它是对内部{{1}的调用如require中定义的那样,Node / Angular-cli无法处理它。

    请注意,在该设置之后,我的应用程序仍然因某些AJAX中的运行时错误而失败,因为browsified client/libquassel.js似乎需要在服务器端设置代理,如libquassel.js这样的网址,这可能是net-browsify应该做什么服务器端,但我没有尝试设置它。

    回复评论

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

    以下是/api/vm/net/connect在原始机器上告诉我的内容

    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 的编译错误,但当我将Angular-CLI更新为

    require

    它编译和工作相同。我所做的只是遵循指令

      

    包" angular-cli"已被弃用并重命名为" @ angular / cli"。

         

    请采取以下措施以避免问题:
      " npm卸载--save-dev angular-cli"
      " npm install --save-dev @ angular / cli @ latest"

    然后按照@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

    的说明更新angular-cli.json

答案 1 :(得分:1)

像魅力一样:

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

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

如果没有index.js,则无法执行此操作:

 require( 'libquassel' );

仅仅因为节点不知道要为您提供什么,所以您需要指定确切的路径,在这种情况下并不是那么糟糕。

另外,请注意,将declare var require;移动到位于src文件夹下的打字文件会更好,因为您可能需要再次声明它,因此最好在那里。< / p>

编辑: 这是我在尝试实例化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 );

这是我的控制台日志:

enter image description here 但话虽如此,我意识到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,如果你谷歌,只有一个名为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成为不公平(空),这就是我们必须创建别名的原因

答案 2 :(得分:0)

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

答案 3 :(得分:0)

关键问题是浏览器化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(未找到)

  

错误:未捕获,未指定的“错误”事件。       在新错误(本机)       在Quassel.n.emit(http://localhost:4200/main.bundle.js:570:4210)[有角度的]       在Socket。 (http://localhost:4200/main.bundle.js:810:19931)[有角度的]       在Socket.EventEmitter.emit(http://localhost:4200/main.bundle.js:573:1079)[angular] ...

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

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