DracoBlue / jsb

A very extendable Toolkit to inject Javascript Behaviour into rendered HTML without Inline Javascript. (jsb was formerly known as JsBehaviourToolkit)
http://dracoblue.net
Other
52 stars 8 forks source link

Webpack can't bundle jsb #32

Closed larslaade closed 6 years ago

larslaade commented 7 years ago

WARNING in ../~/node-jsb/jsb.js 296:20-305:22 Critical dependency: the request of a dependency is an expression

On line number 296 is the require call:

require([key], function(require_result) {
 // ...
}

Any hints or suggestions?

axten commented 7 years ago

hi lars :) we are working on an integration of webpack2 into the nikita generator. Thats work in progress but we already found a solution.

strategy is to ignore jsbs in webpack and include all jsbs by hand. with import-glob its only a single import statement. we suffix all jsbs with .jsb.js to avoid interferences with other modules.

our grunt config looks like that:

        webpack: (function(){

            var webpack = require('webpack');
            var plugins = [
                new webpack.IgnorePlugin(/^(.*)$/, /node-jsb$/)
            ];

            return {
                options: {
                    entry: {
                        main: './<%%= paths.src %>/js/_main.js'
                    },
                    module: {
                        exprContextCritical: false,
                        rules: [
                            {
                                test: /\.js$/,
                                enforce: 'pre',
                                loader: 'import-glob',
                                exclude: /node_modules/
                            },
                                                    ...
                                                ]
                    },
                    resolve: {
                        modules: ['<%%= paths.src %>/js', 'node_modules']
                    }
                },
                dev: {
                                        ...
                    plugins: plugins
                },
                dist: {
                                        ...
                    plugins: plugins
                }
            };
        })()

entry file _main.js looks like this:

import app from './app';
import jsbs from './**/*.jsb.js';
larslaade commented 7 years ago

Hi Benny :)

thank you for your fast response. Using the IgnorePlugin my build is working for now. (But the warning is still there.)

DracoBlue commented 7 years ago

It's important to have jsb.registerHandler in your jsb's, because otherwise it cannot map it properly :(.

axten commented 7 years ago

(But the warning is still there.)

exprContextCritical: false, does the trick ;)

silasjoisten commented 6 years ago

Is here any update? Having the same problem. And i don't want to use: exprContextCritical: false

axten commented 6 years ago

first of all: this is not a bug of jsb (see comments above for a working integration with webpack). exprContextCritical: false just hide the warnings in this approach.

which problems do you have in detail?

silasjoisten commented 6 years ago

my app.js:

(Same thing when i add via yarn add node-jsb)

import jsb from '../js/jsb.js'
global.jsb = jsb;

//Some JSB's

the warning:

www-data@40ac6cc5e7be:~$ yarn build
yarn run v1.5.1
$ encore production
Running webpack ...

 WARNING  Compiled with 1 warnings                                                                       10:31:15

 warning  in ./assets/js/jsb.js

297:20-306:22 Critical dependency: the request of a dependency is an expression

Done in 6.35s.

developer console output:

app.b8ad9cc4.js:24 Uncaught ReferenceError: jsb is not defined
    at Object.<anonymous> (app.b8ad9cc4.js:24)
    at Object.91bm (app.b8ad9cc4.js:24)
    at e (app.b8ad9cc4.js:1)
    at Object.<anonymous> (app.b8ad9cc4.js:24)
    at Object.ET/6 (app.b8ad9cc4.js:24)
    at e (app.b8ad9cc4.js:1)
    at 0418 (app.b8ad9cc4.js:1)
    at app.b8ad9cc4.js:1

app.b8ad9cc4.js:1 Error: Cannot find module "."
    at app.b8ad9cc4.js:24
    at app.b8ad9cc4.js:24
e.oe @ app.b8ad9cc4.js:1
Promise.catch (async)
callHandler @ app.b8ad9cc4.js:24
applyBehaviour @ app.b8ad9cc4.js:24
(anonymous) @ app.b8ad9cc4.js:24

app.b8ad9cc4.js:24 Uncaught (in promise) Error: Cannot find module "."
    at app.b8ad9cc4.js:24
    at app.b8ad9cc4.js:24
axten commented 6 years ago

do you modified your webpack config like in the comment above?

silasjoisten commented 6 years ago

yea i did, but this cant be the solution. This flag just disable the warning messages. And the error in developer console still there

silasjoisten commented 6 years ago

I figuered out that: require is part of webpack and jsb library doesn't use require as webpack wants you to use it.

DracoBlue commented 6 years ago

jsb expects require to behave like require behaves in case of AMD. webpack does not load dynamic versions of modules. So we could create a jsb version, which cannot lazyload requirejs modules.

So basically it's webpacks fault: webpack does not need this feature, neither webpack can use it. Thus it would be great, if webpack wouldn't complain about sourcecode, which it cannot execute ;). Can you fix this by embedding jsb properly with webpack?

silasjoisten commented 6 years ago

webpack does not load dynamic versions of modules

What do you mean with that?

You could use require and import in webpack to dynamically load modules even asynchronously. see https://webpack.js.org/guides/code-splitting/#dynamic-imports

sourcecode, which it cannot execute

Webpack looks for require and import statements to load dependencies and build the dependency tree. So the code does not get executed but webpack tries to look ahead and load the entire dependency tree.

DracoBlue commented 6 years ago

See e.g. https://www.bennadel.com/blog/2402-lazy-loading-requirejs-modules-when-they-are-first-requested.htm.

Implementing it like webpack handles it, would mean that the requirejs lazyloading is not possible anymore. We could try to use https://webpack.js.org/api/module-methods/#require-ensure if it's available. But webpacks error message appears, because webpack tries to guess what the code does. But the jsb source doesn't do, what webpack expects it to do ;).

silasjoisten commented 6 years ago

Okay i solved it like:

custom-jsb.js

const handlers = {};
const eventHandlers = {};

const loadJsbHandler = function (element) {
    let handler = null;
    for (let i = 0; i < element.classList.length; i++) {
        if (element.classList[i].startsWith('jsb_') && element.classList[i].length > 4) {
            handler = element.classList[i].substr(4);
            break;
        }

    }

    const options = JSON.parse(element.dataset.jsb || '{}');

    if (handlers[handler]) {
        handlers[handler](element, options)
    }

};

const jsb = {
    on(key, callback) {
        eventHandlers[key] = eventHandlers[key] || []
        eventHandlers[key].push(callback)
    },
    off(key, callback) {
        if (eventHandlers[key]) {
            const index = eventHandlers[key].indexOf(callback)
            eventHandlers[key].splice(index, 1);
        }
    },
    whenFired(key, callback) {
    // TODO: implement me
    },
    fireEvent(key, payload) {
        (eventHandlers[key] || []).forEach(callback => callback(payload));
    },
    registerHandler(key, callback) {
        handlers[key] = callback;
    },
    load() {
        document.querySelectorAll('.jsb_').forEach(loadJsbHandler);
    }
};

document.addEventListener('DOMContentLoaded', function () {
    jsb.load()
});

export default jsb;

app.js

import jsb from '../js/custom-jsb';
window.jsb = jsb;

require('../js/LoadOverlay.js')
//...

LoadOverlay.js

LoadOverlay = function (domElement, options) {
   // do something
};

jsb.registerHandler('LoadOverlay', LoadOverlay);

Using

<div class="jsb_ jsb_LoadOverlay"></div>
silasjoisten commented 6 years ago

I just didn't know how whenFired is working... maybe some queueing stuff.

Anyway thanks for quick answer! :)

DracoBlue commented 6 years ago

Please don’t reimplement jsb entirely. /cc @oskarstark

DracoBlue commented 6 years ago

Fixed with jsb 3.1.0