最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using a browserified JS library with Angular 2 - Stack Overflow

programmeradmin3浏览0评论

I want to use libquassel () in my Angular 2 project. 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

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.

How can I use this library?

Edit: I'll answer all questions here:

  • My setup is a plain angular-cli project. No fancy stuff, just ng new proj1 and then npm install libquassel --save.
  • My index.html doesn't have anything else that ng new hasn't placed in there.
  • 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).
  • Steps to repro my project:

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

Then add QuasselService to the providers array in app.module.ts. This would be a good demo of my problem, which is how to import libquassel in my QuasselService.

I want to use libquassel (https://github./magne4000/node-libquassel) in my Angular 2 project. 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

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.

How can I use this library?

Edit: I'll answer all questions here:

  • My setup is a plain angular-cli project. No fancy stuff, just ng new proj1 and then npm install libquassel --save.
  • My index.html doesn't have anything else that ng new hasn't placed in there.
  • 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).
  • Steps to repro my project:

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

Then add QuasselService to the providers array in app.module.ts. This would be a good demo of my problem, which is how to import libquassel in my QuasselService.

Share Improve this question edited Mar 19, 2017 at 15:38 alexandernst asked Mar 17, 2017 at 13:58 alexandernstalexandernst 15.1k25 gold badges106 silver badges213 bronze badges 8
  • Can you give more detail about your setup? What does your index.html looks like? Are you using angular-cli? How do you import this module? – eko Commented Mar 19, 2017 at 14:56
  • @echonax Check my edit. You can also reproduce my project, since this is just a plain angular-cli project. – alexandernst Commented Mar 19, 2017 at 15:01
  • update your post with the configuration file you have – Aravind Commented Mar 19, 2017 at 15:13
  • @Aravind which configuration file? – alexandernst Commented Mar 19, 2017 at 15:30
  • systemjs or webpack? – Aravind Commented Mar 19, 2017 at 15:45
 |  Show 3 more ments

4 Answers 4

Reset to default 5 +500

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:

  "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

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

libquassel's custom require is left stuck inside anonymous namespace and you can't access it. Adding it to the scripts section on the other hand, lets libquassel.js to pollute the global namespace (i.e. window) with its require and thus make it work.

So the actual steps to make it work are:

  1. Add client/libquassel.js to the scripts section of angular-cli.json
  2. Use additional require to actually load Quassel module
let Quassel = window['require']('quassel'); // note that usingg require('quassel') leads to pilation 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". Here is a trick that seems to work for me in 'main.ts':

require('../node_modules/libquassel/client/libquassel.js');
let Quassel = window['require']('quassel'); // note that using require('quassel') leads to pilation error
let quasselObj = new Quassel(...);

I needed one more trick to not fail with a pilation 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.

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.

Answer to ments

It looks like you use old version of Angular-CLI and if you upgrade everything should work fine.

Here is what ng --version tells me on my original machine

angular-cli: 1.0.0-beta.28.3
node: 6.10.0
os: win32 x64
@angular/mon: 2.4.10
@angular/piler: 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/piler-cli: 2.4.10

When I tried to copy my original project to a different machine I also got a pilation error about require but when I updated Angular-CLI to

@angular/cli: 1.0.0
node: 6.10.0
os: darwin x64
@angular/mon: 2.4.10
@angular/piler: 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/piler-cli: 2.4.10

it piled and worked the same. What I did is just followed the instruction

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"

and then updated angular-cli.json following the instructions by ng serve

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.

When there is not index.js , you can't do this :

 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; to your typings file located under the src folder, because you might need to declare it again , so it's better be there.

EDIT : Here is what I found after trying to instantiate the Quassel like bellow :

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 :

in line 10, they're doing this :

   var net = require('net');

And looking their package.json, there is no such a thing as net and there is 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 !!!!

** ********** UPDATE : ********** **

What exactly needs to be done :

1- run ng eject

that will generate a webpack.conf.js inside your root directory.

2- inside that find resolve property and add :

 "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 :

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 :

"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.

Angular-cli uses 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.

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

If you do that, you can get at it by adding declare var Quassel :any; in your src/typings.d.ts or ponent.

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. That conflicts with standard require function.

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.

Then run a search and replace in these files to change ALL occurrences of require to _quasselRequire_

You would do this for both libquassel.js and libquassel.min.js.

To utilise this you would do something like this in 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)

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. (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.

Note: the name _quasselRequire_ can be anything that's appropriate to you.

发布评论

评论列表(0)

  1. 暂无评论