Jump to content
Sign in to follow this  
KTachyon

Node Webkit com Require JS

Recommended Posts

KTachyon

Para quem não conhece, o Node Webkit é uma aplicação baseada no Chromium que permite executar aplicações Web de forma a que aparentem ser nativas. No fundo é um container para aplicações Web que podem executar num sistema operativo fora do browser.

Uma das coisas interessantes deste container é fornecer um contexto Node.js partilhado com o contexto do Javascript, e o container já existe compilado para Mac OS X, Windows e Linux, e pode ser utilizado facilmente para distribuir aplicações web independentes para estes sistemas operativos.

Podem aceder à página do projecto em https://github.com/rogerwang/node-webkit

Ora, um dos grandes problemas que, aparentemente, ninguém conseguiu resolver é o facto de que o Node.js fornece o seu próprio require, que ocupa o mesmo namespace que o require JS. Ou seja, em teoria, se pretendem utilizar toda a funcionalidade do Node Webkit, não podem utilizar o require JS. Ou, se pretendem utilizar o require JS, não podem utilizar o require do Node. Pelo menos, em teoria...

As soluções para evitar o conflito de requires que existiam eliminavam um dos requires, porque algum deles teria que ocupar o namespace, e mudar o namespace de um deles não é solução pois as bibliotecas que utilizam outras dependências carregadas pelo require acedem ao namespace conhecido do require (window.require).

Exemplo:

Imaginem que uma dependência do Node "A" tem outra dependência "B". Imaginem também que mudaram o require do Node (em window.require) para window.requireNode) e que o require JS ficou no window.require.

Para importarem a dependência "A" irão fazer:

var depA = requireNode("A");

O que vai acontecer é que, na consola, vão receber um erro do require JS, que não consegue carregar o "B". Isto porque, internamente, a biblioteca "A" vai pedir a dependência "B" com window.require, onde está o require JS, em vez de utilizar o window.requireNode.

Da mesma forma, se mudarem o namespace do require JS, vão ter o mesmo problema na cadeia de dependências.

Muitos podem achar que a existência de um container web já é valor suficiente para o Node Webkit, mas a realidade é que não se consegue fazer tudo sem a capacidade do Node.js, como a possibilidade de ter um servidor local para servir ranges de conteúdos dinâmicos (video, audio), inutilizando a capacidade de se poder fazer seek no conteúdo (isto é um exemplo comum, mas existem muitos outros).

Agora vou explicar o que é que eu quis dizer com "em teoria". A verdade é que, dentro de um dos contextos de um require, só necessitam verdadeiramente de utilizar esse require (o desse contexto). Logo, é perfeitamente aceitável que, chamando um require, todos os require seguintes até ao retorno do require inicial devem ser do mesmo tipo. Ou seja, é possível fazer o seguinte:

function setupRequireFallback() {
   window.require_js = window.require;

   window.fallbackRequire = function(a, b, c, d) {
       var result;

       try {
           requireFromJS(function() { result = require(a, b, c, d); });
       } catch (err) {
           requireFromNode(function() { result = require(a, b, c, d); });
       } finally {
           window.require = window.fallbackRequire;
       }

       return result;
   }

   window.fallbackRequire.config = window.require.config;

   // Method swizzling power 

   window.requireFromNode = function(requireCall) {
       window.require = window.requireNode;
       requireCall();
       window.require = window.fallbackRequire;
   }

   window.requireFromJS = function(requireCall) {
       window.require = window.require_js;
       requireCall();
       window.require = window.fallbackRequire;
   }

   window.require = window.fallbackRequire;
}

Portanto, aqui fica a solução.

Claro que, esta solução tem o potencial para ser desastrosa caso se misture Node.js no processo de inicialização de dependencia Javascript, mas misturar procedimentos de Node.js com Javascript não me parece boa prática e é altamente desaconselhado.

Na eventualidade de ser mesmo necessário (expressando todas as minhas dúvidas de que seja mesmo necessário em qualquer situação - sugiro que repensem 10 vezes aquilo que pretendem fazer), teriam que implementar uma stack de requires em que, de cada vez que fazem a troca do require, chamando o método específico (requireFromJS ou requireFromNode) em vez do fallback, devem fazer push do require actual para uma stack, e remover da stack após o carregamento da dependência:

function setupRequireFallback_v2() {
   var requireStack = [];

   window.require_js = window.require;

   window.pushRequire = function(require) {
       requireStack.push(window.require);
       window.require = require;
   }

   window.popRequire = function() {
       window.require = requireStack.pop();
   }

   window.stackAndCall = function(require, call) {
       pushRequire(require);
       call();
       popRequire();
   }

   window.fallbackRequire = function(a, b, c, d) {
       var result;

       try {
           requireFromJS(function() { result = require(a, b, c, d); });
       } catch (err) {
           requireFromNode(function() { result = require(a, b, c, d); });
       } finally {
           window.require = window.fallbackRequire;
       }

       return result;
   }

   window.fallbackRequire.config = window.require.config;

   window.requireFromNode = function(requireCall) {
       stackAndCall(window.requireNode, requireCall);
   }

   window.requireFromJS = function(requireCall) {
       stackAndCall(window.require_js, requireCall);
   }

   window.require = window.fallbackRequire;
}

E precisam também de se lembrar que, se estiverem dentro de um contexto que recebe o require como variável, quando querem fazer uma chamada específica a um require do outro contexto, têm sempre que indicar explicitamente que é esse require que pretendem:

define([
   'require',
], function (require) {

   // ...

   var path;

   requireFromNode(function() { path = window.require("path"); });

   // ...

}

Happy coding.

Edited by KTachyon

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.