Manually import controller

Hey there!

I have a pretty basic rails + webpacker app, 100% following webpacker tutorial. When i’m trying to load an external controller (following this example) which looks like this:

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "toggleBtn", "moreFilters" ]

  toggleMoreFilters (e) {
    e.preventDefault()
    this.moreFiltersTarget.classList.toggle('d-none')
  }

  submitForm (e) {
    if (e.key == 'Enter') {
      this.element.submit()
    }
  }
}

webpacker throws:

ERROR in ./node_modules/@beehivecms/core/frontend/controllers/search_form_controller.js
Module parse failed: Unexpected token (4:17)
You may need an appropriate loader to handle this file type.
|
| export default class extends Controller {
|   static targets = [ "toggleBtn", "moreFilters" ]
|
|   toggleMoreFilters (e) {
 @ ./app/javascript/packs/beehive_admin.js 13:0-100
 @ multi (webpack)-dev-server/client?http://localhost:3035 ./app/javascript/packs/beehive_admin.js
webpack: Failed to compile.

Is there anything obvious i forgot to do in order to be able to include an external controller manually?

Thanks in advance!

I’m in the car so sorry if my answer is not complete.

Problem is most likely something to do with not importing a loader in webpacker. Google the error line that starts with “You May need an appropriate loader …” and see how others have solved the problem.

It that doesn’t work, you might want to dump your webpacker config here.

Do you have the Babel configuration set up?
https://stimulusjs.org/handbook/installing#using-babel

thank you for replies guys!

that’s exactly how i would normally do that but in this case, this error has no more details than posted in original post. Normally, such error includes line like you need to have xxx loader installed in order to include this file so it’s pretty easy to find a solution but here, it’s just a generic “you need a loader”, without specifying what loader it needs :slight_smile:

What’s weird in here is that i had this file in app/javascript/controllers and it was working just fine but it broke after moving it out of this directory and importing manually - is that normal? Sorry if i’m asking weird questions but my webpacker skills are not yet sufficient to fully know what i’m doing :slight_smile:

My webpacker config is the one generated by rails webpacker:install:stimulus - which file exactly are you asking for @davedkg ?


@adrienpoly after adding @babel/plugin-proposal-class-properties, webpack raises an exception that it needs babel in version 7.0.0 while webpacker depends on ^6.26.3 so i’m affraid i can’t do much about that? :confused:

this is my .babelrc conf file

{
  "presets": [
    [
      "env",
      {
        "modules": false,
        "targets": {
          "node": "current"
        },
        "useBuiltIns": true
      }
    ]
  ],
  "plugins": [
    "transform-object-rest-spread",
    ["transform-class-properties", { "spec": true }]
  ]
}

The one I pointed before will be applicable with webpacker 4.0. Currently I suppose you have a 3.5 something.

Not sure to understand exactly what you are doing. Why do you want to move your controller outside of app/javascript/controllers?

If you have a controller in a node module package what you can do is import it within application.js and register it manually or extend it.
You can see an example is this package I build to wrap Flatpickr.
Maybe it can help you

1 Like

that’s exactly what i’m trying to do - i want to move a set of my controllers to a separate node module, import them manually and register as a local controllers. And when they are in a normal controllers directory, everything works great. But when i move the exact same file to an npm package and import it with import SearchController from 'my_package/src/search_controller.js' in my main application.js file (the same one responsible for loading everything from ./controllers folder), it throws this error quoted in OP.

What i completely can’t understand is why it works fine when in local controllers dir while it breaks when moved outside of it and imported manually. It seems suspicious to me.

Can such “raw” file be imported without updating to webpacker 4.0.?

I understand this starts to be a webpack issue rather than stimulus issue but it’s kinda related to the solution posted in official stimulus guides so it either should be resolvable or maybe more explicitly documented in the stimulus guides? :slight_smile:


My files

package.json

{
  "name": "beehive-demo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "@xxx/core": "./beehive", // <-- my extracted controller is in this package
    "@rails/webpacker": "3.5",
    "stimulus": "^1.1.1"
  },
  "devDependencies": {
    "webpack-dev-server": "2.11.2"
  }
}

.babelrc

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": "> 1%",
        "uglify": true
      },
      "useBuiltIns": true
    }]
  ],

  "plugins": [
    "syntax-dynamic-import",
    "transform-object-rest-spread",
    ["transform-class-properties", { "spec": true }],
  ]
}

application.js

import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

import { SearchFormController } from '@xxx/core/frontend/controllers/search_form_controller' // <-- that's the file

const application = Application.start()
const context = require.context("controllers", true, /.js$/)
application.load(definitionsFromContext(context))

The problem you are facing is that Webpacker (the Rails wrapper on top of Webpack) does not transpiles files from node_modules (https://github.com/rails/webpacker/issues/1260)

To move a controller to a node module you need to somehow build it and it.

As an example here is how it looks for my package
https://github.com/adrienpoly/stimulus-flatpickr/blob/master/dist/stimulus-flatpickr.m.js#L137

The code is very different from the source

I am now using Rollup to transpile but I started with Microbundle that was extremely easy to use

1 Like

You can use the pre-release version of Webpacker v4, which uses Babel v7. Or, use the previous version of the Babel plugin for v6: https://babeljs.io/docs/en/6.26.3/babel-plugin-transform-class-properties.

Stimulus docs updated for Babel v6 → v7 here: Docs: Freshen installation guide for Babel 7 · hotwired/stimulus@1d275fc · GitHub

1 Like

thank you @javan


@adrienpoly yeah, microbundle was exactly what i was looking for. Configuring webpacker/rollup to play nice with static syntax turned out to be 100 times too complex for me to deal with and microbundle seems to somehow do everything with literally zero configuration. Nice. Thanks so much for everything and for clarification!

We can consider this thread as resolved (too bad there is no option to set topic as resolved plugin installed on this discourse instance)