Home > Back-end >  Problem trying to access javascript modules inside a Backbone.js view template using Webpack
Problem trying to access javascript modules inside a Backbone.js view template using Webpack

Time:11-02

I'm doing some maintenance on a Java web-application composed of JSON APIs and a UI based on Backbone.js and React, bundled using Webpack.

This application has a single main page, index.html and a corresponding main.js. This main.js import few Javascript modules which themselves imports bunch of other modules and roughly look like this:

import Configuration from "com/MyConfiguration";

Configuration.loadEventHandlers();

This configuration module imports itself a bunch of others, which eventually imports a number of Views that extend Backbone views. They look like this:

const MainView = AbstractView.extend({
    template: "common/DefaultBaseTemplate",
    baseTemplate: "common/MainTemplate",
    data: {},
    events: {
        "click input[type=submit]": "formSubmit"
    },

These views load Handlebars templates like this one:

<div >
    <p >
        {{#if theme.settings.footer.showversion}}
            {{version}}
            <br/>
        {{/if}}
        {{theme.settings.footer.copyright}}
    </p>
</div>
<script type="text/javascript">
  SetTimeout(function(){
    doSomeTrick();
  }, 3000);
</script>

They also loads Handlebars partials like this one:

<button 
        type="button"
        {{#if disabled}}disabled="{{disabled}}"{{/if}}
        {{#if data}}data-{{data}}{{/if}}>
     {{#if icon}}<i ></i> {{/if}}{{t title}}
</button>
<script type="text/javascript">
  SetTimeout(function(){
    doSomeTrick();
  }, 3000);
</script>

Finally we have a custom javascript module "custom.js" that look like this:

import $ from "jquery";

export function doSomeTrick() {
  // some fancy code using jquery
}

The structure of the app look like this:

- config
  - webpack => webpack config
- src
  - js
    - custom => customized javascript sources, example: custom.js
    - com => product sources, including Views, example: AbstractView.js
  - resources
    - css
    - images
    - partials => HTML Handlebars Partials, example: _Button.html
    - templates => HTML Handlebars Templates, example: Footer.html

I'm in the process to migrate the application to a newer version from an old version which wasn't bundled with Webpack. I then realized that some Templates and Partials included some custom javascript, that reference the custom Javascript module "custom.js". The problem is that these references to Javascript functions that are located inside the custom module "custom.js" are not resolved anymore in the new version with webpack. If I call these Javascript functions directly inside main.js or inside AbstractView.js after importing custom.js, it works well. However I don't understand how I can import this module inside the Handlebars templates and partials. I guess one solution would be to copy this js library directly to the dist directory and reference it inside the templates, but it kind of defeat the point of using Webpack in the first place.

What would be the correct way to load this module inside the templates and partials? Do I need to use a special Webpack loader for that? I don't think it would help to use an HtmlWebpackPlugin, as I don't need an extra HTML in the dist directory, but rather the templates and _partials to be embedded in the javascript of the application, but with working references to the custom library.

I tried without explicit import to the module inside the Templates and Partials, as I thought the module would be available if imported in the view, but it doesn't work.

I also tried explicitly importing the module inside the Templates and Partials, with something like this:

<script src="custom/custom.js"></script>

but it doesn't work as the browser attempt to resolve this path, which doesn't exist, as everything is bundled using webpack.

I have been looking around for long time now, but cannot find a solution to this problem. Any help would be greatly appreciated.

Thanks!

CodePudding user response:

I found a solution to the problem, although probably not the cleanest.

The key to the problem seems to be about the scoping of variables in Javascript. Indeed javascript modules are visible only in the scope where they are imported, that's why you can't see imported modules functions and variables in the Javascript console.

In my case, the views are a virtual construction of Backbone and the templates and partials are dynamically bound to some elements of the DOM ($el). In the template and partials HTML context, my experience was that it's possible to import modules using such a statement:

<script src="/path/to/module"></script>

However this approach has limitation, as one cannot write the scripts and module references directly in the Template or Partial but must create a Javascript module for each of them. Using following statement didn't work for me:

<script type="module">
  import { myExportedNamedFunction } from "myModule";
  myExportedNamedFunction();
</script>

This throws an error, stating that myModule doesn't export such a function. It works correctly if run the same outside the HTML context, for example in my "main.js". My assumption so far is that the Javascript code in the HTML code is not able to interpret the module code correctly, although the javascript resolution itself works (we can see the 200 in the network trace).

The solution I found was to import the Module directly in the Global context and to reference it from there.

Main.js

import * as myModule from "myModule";
window.myModule = myModule

Template.html, directly in the Javascript:

myModule.myFunction()

I hope this can help someone, and would look forward for a hint about a cleaner approach using Webpack.

  • Related