Использование браузера JS-библиотеки с Angular 2
Я хочу использовать libquassel (https://github.com/magne4000/node-libquassel) в моем проекте Angular 2. Библиотека просматривается, поэтому теоретически она должна работать, но я не уверен, как ее импортировать в свой проект.
Я попытался добавить в свой typings.d.ts
declare module 'libquassel';
а затем импортируйте библиотеку с помощью
import * as Quassel from 'libquassel';
но я получаю
EXCEPTION: net.Socket is not a function
когда я пытаюсь запустить свой код, который, я считаю, является другой библиотекой, которая просматривает встроенные в файл client/libquassel.js
.
Как я могу использовать эту библиотеку?
Изменить: я отвечу на все вопросы здесь:
Затем добавьте QuasselService
в массив providers
в app.module.ts
.
Это было бы хорошей демонстрацией моей проблемы, а именно, как импортировать libquassel
в мой QuasselService
.
Ответы
Ответ 1
Обновить (исправить, на этот раз для реального)
Есть очень веская причина, почему это не работает в вашем коде: потому что я солгал вам. Итак, вот мой настоящий чит на случай, если вы еще не "разобрались" в нем.
Мне все еще нужно 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 custom require
остается застрявшим внутри анонимного пространства имен, и вы не можете получить к нему доступ. Добавив его в раздел scripts
, с другой стороны, пусть libquassel.js загрязняет глобальное пространство имен (т.е. window
) своим require
и тем самым заставляет его работать.
Итак, действительные шаги для его работы:
- Добавьте клиент /libquassel.js в скрипты
section
из angular-cli.json
- Используйте дополнительный
require
для фактического загрузки модуля Quassel
let Quassel = window['require']('quassel'); // note that usingg require('quassel') leads to compilation error
let quasselObj = new Quassel(...);
Вот моя попытка. Похоже, вам нужно require
"quassel" 2 раза: первый раз загрузить JS из "../node_modules/libquassel/client/libquassel.js" и второй раз, чтобы разрешить переопределенное require
от этого JS фактически разрешает "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
для второго вызова, так как это вызов внутреннего require
, как определено внутри client/libquassel.js
и 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
он скомпилирован и работает одинаково. Я только что выполнил инструкцию
Пакет "angular -cli" устарел и переименован в "@ angular/cli".
Чтобы избежать проблем, выполните следующие действия:
" npm uninstall --save-dev Angular -cli"
" npm install --save-dev @angular/cli @latest"
а затем обновить angular-cli.json
в соответствии с инструкциями ng serve
Ответ 2
Работает как шарм:
declare var require;
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
Глядя на папку libquassel
в node_module, понял, что в корневом каталоге нет index.js
.
Если нет index.js
, вы не можете сделать это:
require( 'libquassel' );
Просто потому, что node не знает, что вам нужно, поэтому вам нужно указать точный путь, который в этом случае не так уж плох.
Кроме того, обратите внимание, что лучше перемещать declare var require;
в файл с образцами, расположенный под папкой src, потому что вам может потребоваться его снова объявить, поэтому лучше быть там.
ИЗМЕНИТЬ:
Вот что я нашел после попытки создать экземпляр 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, потому что ясно, что они упомянули неправильный узел_модуль, который, если вы 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
undefiend (empty) и поэтому нам нужно создать псевдоним.
Ответ 3
Angular -cli использует webpack
вам нужно будет добавить JS файл в приложения [0].scripts в ваш файл angular -cli.json, который затем упаковывается, как если бы он был загружен тегом.
apps:[
{
...
"scripts": [
"../node_modules/libquassel/client/libquassel.js"
],
Если вы это сделаете, вы можете получить его, добавив declare var Quassel :any;
в свой src/typings.d.ts или компонент.
let quassel = new Quassel("localhost", 4242, {}, function(next) {
next("user", "password");
});
quassel.connect();
Ответ 4
Ключевой проблемой является браузерная библиотека libquassel
содержит внутри нее глобальную функцию require
. Это противоречит стандартной функции require
.
Существует много способов решения этой проблемы, но одно решение - скопировать /libquassel/client/libquassel.js
(и мини-версию) в каталог /src/app/
.
Затем запустите поиск и замените в этих файлах, чтобы изменить ВСЕ вхождения от require
до _quasselRequire_
Вы сделаете это как для libquassel.js
, так и libquassel.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 (не найдено)
и
Ошибка: нечистое, неопределенное событие "ошибка". при новой ошибке (native) в Quassel.n.emit(http://localhost:4200/main.bundle.js:570:4210) [angular] в Socket. (http://localhost:4200/main.bundle.js:810:19931) [angular] на Socket.EventEmitter.emit(http://localhost:4200/main.bundle.js:573:1079) [angular]...
Но, как я понимаю, это довольно нормально, если у меня нет Express и т.д.
Примечание: имя _quasselRequire_
может быть любым, что вам подходит.