-1

I'm trying to use page-specific module with inline script but getting an error.

At first I have created a module and stored it in assets/js/tags.js

class TaggedImage {
    constructor(image) {
        this.image = image
    }
    ...
}
export {TaggedImage}

Then I added this module in webpack.config.js to specific route:

Encore
    ...
    .addEntry('photo_page', './assets/js/tags.js')

Now I'm trying to use this module with inline script in twig template:

<script>
    const myImage = new TaggedImage(document.getElementById('photoImage'));
    const tags = [
            {x:0.5, y:0.5, width:0.15, height:0.22},
            {x:0.65, y:0.33, width:0.13, height:0.19},
            {x:0.1222, y:0.398, width:0.10, height:0.335}
        ];
    myImage.addTags(tags).render();
</script>

Then I ran npm run dev in the terminal and it finished without errors.

...and after refreshing the page I get an error in the console:

Uncaught ReferenceError: TaggedImage is not defined

I noticed that my code is added to /public/build/photo_page.js but I don't see any mention of this file in page source.

Community
  • 1
  • 1

1 Answers1

-1

There are two things to your problem. The first one is that besides defining the entry in webpack.config, you have to explicitly import your javascript in your html.

You can do that with the twig helper function encore_entry_script_tags as described in the page specific scripts section of the manual.

So you would add:

{{ encore_entry_script_tags('photo_page') }}
<script>
// Here goes your script
</script>

Or override your block, if you have one, and call {{ parent() }} to include any additional scripts you require in all pages. Note that the entry tag will add the defer attribute by default, as configured in config/packages/webpack_encore.yaml, so you'll need to take that into account and wrap your script to fire on the load event.

The second one is that webpack doesn't expose modules to the global namespace. For that you would have to do it explicitly in your module:

// Instead of exporting the module, you export it to the global scope
// (the browser window in this case)
global.TaggedImage = TaggedImage;
msg
  • 7,863
  • 3
  • 14
  • 33
  • Thanks! Worked like a charm. Also I had to wrap my inline code into ```window.onload = function() { ... }``` – Nikita Bulatenko Jan 07 '22 at 13:47
  • @NikitaBulatenko yes, that's because `encore_entry_script_tags` adds the attribute `defer` by default. This is controlled by the `config/packages/webpack_encore.yaml` configuration file. – msg Jan 07 '22 at 14:01