简体   繁体   English

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

[英]Using a browserified JS library with Angular 2

I want to use libquassel ( https://github.com/magne4000/node-libquassel ) in my Angular 2 project. 我想在我的Angular 2项目中使用libquassel( https://github.com/magne4000/node-libquassel )。 The library is browserified, so in theory it should work, but I'm not really sure how to import it in my project. 该库是浏览器化的,所以理论上它应该可以工作,但我不确定如何在我的项目中导入它。

I tried adding to my typings.d.ts 我尝试添加到我的typings.d.ts

declare module 'libquassel';

and then importing the library with 然后导入库

import * as Quassel from 'libquassel';

but I get 但我明白了

EXCEPTION: net.Socket is not a function

when I try to run my code, which I believe is another library that browserify embedded in the client/libquassel.js file. 当我尝试运行我的代码时,我认为这是另一个浏览嵌入在client/libquassel.js文件中的库。

How can I use this library? 我该如何使用这个库?

Edit : I'll answer all questions here: 编辑 :我会在这里回答所有问题:

  • My setup is a plain angular-cli project. 我的设置是一个简单的角度cli项目。 No fancy stuff, just ng new proj1 and then npm install libquassel --save . 没有花哨的东西,只需要ng new proj1然后npm install libquassel --save
  • My index.html doesn't have anything else that ng new hasn't placed in there. 我的index.html没有任何ng new东西没有放在那里。
  • I tried importing the library with import * as Quassel from 'libquassel' and var Quassel = require('quassel') (and permutations of those), without any luck (errors varying from unknown function 'require' to can't find module lib|quassel ). 我尝试使用import * as Quassel from 'libquassel'var Quassel = require('quassel')导入库(以及那些的排列),没有任何运气(错误从unknown function 'require'can't find module lib|quassel )。
  • Steps to repro my project: 重新制作我的项目的步骤:

     ng new test cd test npm install libquassel --save ng gs quassel 

Then add QuasselService to the providers array in app.module.ts . 然后添加QuasselServiceproviders在阵列app.module.ts This would be a good demo of my problem, which is how to import libquassel in my QuasselService . 这将是我的问题的一个很好的演示,这是如何导入libquasselQuasselService

Update (fix it, this time for real) 更新 (修复它,这次真实)

There is a very good reason why it doesn't work in your code: because I lied to you. 有一个很好的理由说明它在你的代码中不起作用:因为我欺骗了你。 So here is my real cheat in case you didn't "diffed" it yourself yet. 所以这是我真正的作弊,如果你还没有自己“贬低”它。

I still need to require libquassel 2 times but the first time is done not by the call to require which is useless but by adding it to angular-cli.json to the scripts section: 我还需要require libquassel 2倍,但第一次由呼叫做不完, require哪些是无用的,但将它添加到angular-cli.jsonscripts部分:

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

This is important because "client/libquassel.js" declares its own require but do not explicitly exports it so if you do 这很重要,因为“client / libquassel.js”声明了自己的require但是没有明确地将它导出,所以如果你这样做

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

libquassel's custom require is left stuck inside anonymous namespace and you can't access it. libquassel的自定义require被卡在匿名命名空间内,您无法访问它。 Adding it to the scripts section on the other hand, lets libquassel.js to pollute the global namespace (ie window ) with its require and thus make it work. 另一方面,将它添加到scripts部分,让libquassel.js用其require污染全局命名空间(即window ),从而使其工作。

So the actual steps to make it work are: 所以实现它的实际步骤是:

  1. Add client/libquassel.js to the scripts section of angular-cli.json 将client / libquassel.js添加到angular-cli.json的scripts section
  2. Use additional require to actually load Quassel module 使用其他require实际加载Quassel模块
let Quassel = window['require']('quassel'); // note that usingg require('quassel') leads to compilation error
let quasselObj = new Quassel(...);

Here is my attempt. 这是我的尝试。 It looks like you need to require "quassel" 2 times: first time to load the JS from "../node_modules/libquassel/client/libquassel.js" and second time to let the overridden require from that JS actually resolve "quassel". 它看起来像你需要require “quassel” 2次:第一次从“../node_modules/libquassel/client/libquassel.js”和第二次让重写加载JS require从实际JS解析‘quassel’ 。 Here is a trick that seems to work for me in 'main.ts': 这是一个似乎在'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(...);

I needed one more trick to not fail with a compilation error: particularly I had to use window['require'] instead of just require for the second call as it is a call for the inner require as defined inside client/libquassel.js and Node/Angular-cli alone can't handle it. 我还需要一个不会因编译错误而失败的技巧:特别是我必须使用window['require']而不是仅require第二次调用,因为它是对client/libquassel.js定义的内部require的调用,仅Node / Angular-cli无法处理它。

Note that after that setup my application still failed with a runtime error in some AJAX because browsified libquassel.js seem to require a proxy set up on the server-side at URL like /api/vm/net/connect and this is probably what server-side of the net-browsify should do but I didn't try to set it up. 请注意,在该设置之后,我的应用程序仍然在某些AJAX中出现运行时错误,因为browsified libquassel.js似乎需要在服务器端设置代理,例如/api/vm/net/connect ,这可能就是服务器net-browsify应该这样做,但我没有尝试设置它。

Answer to comments 回答评论

It looks like you use old version of Angular-CLI and if you upgrade everything should work fine. 看起来你使用旧版本的Angular-CLI,如果你升级一切都应该工作正常。

Here is what ng --version tells me on my original machine 这是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

When I tried to copy my original project to a different machine I also got a compilation error about require but when I updated Angular-CLI to 当我尝试将原始项目复制到另一台机器时,我也遇到了关于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

it compiled and worked the same. 它编译和工作相同。 What I did is just followed the instruction 我所做的就是遵循指示

The package "angular-cli" has been deprecated and renamed to "@angular/cli". “angular-cli”包已弃用,并重命名为“@ angular / cli”。

Please take the following steps to avoid issues: 请采取以下步骤以避免问题:
"npm uninstall --save-dev angular-cli" “npm uninstall --save-dev angular-cli”
"npm install --save-dev @angular/cli@latest" “npm install --save-dev @ angular / cli @ latest”

and then updated angular-cli.json following the instructions by ng serve 然后按照ng serve的说明更新angular-cli.json

Works like a charm : 奇迹般有效 :

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

Looking at the libquassel 's folder in node_module, realised that there is no index.js in the root directory. 查看libquassel中的libquassel文件夹,意识到根目录中没有index.js

When there is not index.js , you can't do this : 如果没有index.js则无法执行此操作:

 require( 'libquassel' );

Simply because node doesn't know what to pull in for you, so you'd need to specify the exact path, which is not that bad in this case. 仅仅因为节点不知道要为您提供什么,所以您需要指定确切的路径,在这种情况下并不是那么糟糕。

Also , note that it's better to move declare var require; 另外,请注意移动declare var require;更好declare var require; to your typings file located under the src folder, because you might need to declare it again , so it's better be there. 到你位于src文件夹下的打字文件,因为你可能需要再次声明它,所以最好是在那里。

EDIT : Here is what I found after trying to instantiate the Quassel like bellow : 编辑:这是我在尝试实例化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 );

And here is my console log : 这是我的控制台日志:

在此输入图像描述 But having said that, I realised that there is a problem inside the libquassel.js , as bellow : 但话说回来后,我意识到libquassel.js中存在一个问题,如下:

in line 10, they're doing this : 在第10行,他们这样做:

   var net = require('net');

And looking their package.json, there is no such a thing as net and there is net-browserify-alt ; 看看他们的package.json,没有net这样的东西,并且有net-browserify-alt ;

So if they change that import to : 因此,如果他们将导入更改为:

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

Everything will work. 一切都会奏效。

Having said that, obviously you don't want to edit your node_module, but I'm really surprised of how this really works even outside of angular and webpack , because clearly they've mentioned a wrong node_module which if you google , there is only one package named net which I had a look and it's empty and dummy !!!! 话虽如此,显然你不想编辑你的node_module,但我真的很惊讶甚至在angular和webpack之外它是如何工作的,因为很明显他们提到了一个错误的node_module,如果你google,只有一个名为net软件包,我看了一眼,它是空的,虚拟的!

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

What exactly needs to be done : 究竟需要做什么:

1- run ng eject 1- run ng eject

that will generate a webpack.conf.js inside your root directory. 这将在根目录中生成webpack.conf.js

2- inside that find resolve property and add : 2-在里面找到resolve属性并添加:

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

so your resolve will probably look like : 所以你的决心可能会是这样的:

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

3- import and use it : 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 );

NOTE : 注意 :

Having a look at webpack configuration, seems like webpack likes to override couple of modules : 看看webpack配置,似乎webpack喜欢覆盖几个模块:

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

I don't exactly know why, but this list is in the webpack config and seems to be making net to be undefiend ( empty ) and that's why we had to create an alias. 我不知道为什么,但这个列表在webpack配置中,似乎是使net变为undefiend(空),这就是为什么我们必须创建一个别名。

Angular-cli uses webpack Angular-cli使用webpack

you will need to add the JS file to apps[0].scripts in your angular-cli.json file, which WebPack then bundles as if it were loaded with a tag. 您需要将JS文件添加到angular-cli.json文件中的apps [0] .scripts中,然后将WebPack捆绑为就像加载了标记一样。

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

If you do that, you can get at it by adding declare var Quassel :any; 如果你这样做,你可以通过添加declare var Quassel :any;来获得它declare var Quassel :any; in your src/typings.d.ts or component. 在你的src / typings.d.ts或组件中。

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

The key issue is the browserified libquassel library contains within it a global require function. 关键问题是浏览器化的libquassel库中包含全局require函数。 That conflicts with standard require function. 这与标准require功能冲突。

There are many ways of handling this but one solution would be to copy /libquassel/client/libquassel.js (and the minified version) to your /src/app/ directory. 有很多方法可以解决这个问题,但一种解决方案是将/libquassel/client/libquassel.js (和缩小版本)复制到/src/app/目录。

Then run a search and replace in these files to change ALL occurrences of require to _quasselRequire_ 然后运行搜索并替换这些文件以将所有require更改更改为_quasselRequire_

You would do this for both libquassel.js and libquassel.min.js . 您可以为libquassel.jslibquassel.min.js执行此libquassel.min.js

To utilise this you would do something like this in quassel.service.ts : 要使用它,你可以在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';
  }
}

This by itself results in the error: 这本身会导致错误:

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

and

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

But as I understand it this is fairly normal given I haven't Express etc. set up. 但据我所知,这是相当正常的,因为我没有设置Express等。

Note: the name _quasselRequire_ can be anything that's appropriate to you. 注意:名称_quasselRequire_可以是适合您的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM