Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to import vendor library to use in Stimulus controller, Asset Pipeline version #51

Closed
turgs opened this issue Feb 26, 2021 · 3 comments

Comments

@turgs
Copy link

turgs commented Feb 26, 2021

I'm using Stimulus in Rails 6 via the Asset Pipeline and want to use either momentjs or dayjs library within my controller. How do I import those?

I've tried saving the dayjs.min.js file to vendors/assets/javascripts/dayjs/dayjs.min.js, but do I need to add anything to app/assets/config/manifest.js? or maybe app/assets/javascripts/importmap.json.erb

manifest.js looks like this:

//= link_tree ../javascripts
//= link_tree ../images
//= link_directory ../javascripts .js

importmap.json.erb looks like this:

{
  "imports": { 
    "turbo": "<%= asset_path "turbo" %>",
    <%= importmap_list_with_stimulus_from "app/assets/javascripts/controllers", "app/assets/javascripts/libraries" %>
  }
}

This is the bit where I'm stuck. I get the same error:

Failed to autoload controller: timepicker 
Error: Unable to resolve specifier 'dayjs' from 
http://my.127.0.0.1.xip.io/assets/controllers/timepicker_controller-b2e267b01d1aad58218fa00a049e456870db49eda347728b16443be29c59682f.js

I think then once the library is "available", I should be import it to be available in my Stimulus controller with 🙏 :

  import { Controller } from "stimulus"
+ import dayjs from 'dayjs'
  export default class extends Controller {
  ...

If I try the following with importmap.json.erb:

  {
    "imports": { 
      "turbo": "<%= asset_path "turbo" %>",
+    "dayjs": "<%= asset_path "dayjs/dayjs.min.js" %>",
      <%= importmap_list_with_stimulus_from "app/assets/javascripts/controllers", "app/assets/javascripts/libraries" %>
    }
  }

The error changes to the following when I reload the page:

Failed to autoload controller: timepicker SyntaxError: import not found: default
@seanpdoyle
Copy link
Contributor

seanpdoyle commented Feb 26, 2021

This engine is built to leverage ECMAScript Modules.

If your project has an external dependency, you have several options.

First, declare the import statement in the module that needs it: import day from "dayjs".

Next, configure your server so that it knows how to resolve the dayjs package name. You have several options, including:

  • downloading the source as a vendored package or a gem that bundles its assets, configuring how to resolve the name in your importmap.json with a project-relative path (e.g. "dayjs": asset_path("dayjs/dayjs.min.js")), then serving it from the Rails application
  • downloading the source as a node_modules package, configuring how to resolve the name in your importmap.json with a project-relative Webpacker path (e.g. "dayjs": asset_pack_path("dayjs/dayjs.min.js")), then serving it from the Rails application
  • configuring how to resolve the name in your importmap.json with an absolute URL (e.g. "dayjs": "https://cdn.skypack.dev/dayjs")
  • declaring the import statement directly in your module with an absolute URL (e.g. import day from "https://cdn.skypack.dev/dayjs")

Have you tried any of these other alternatives?

@turgs
Copy link
Author

turgs commented Feb 28, 2021

Ok i've finally figured out 👏 how to import a library. Maybe this is common knowledge for others but ES6 is a brave new world for me. I'm generally stuck back in Year 2000 Javascript.

I didn't want to use a gem that bundled the library for the asset pipeline, and I didn't want to call skypack or a remote CDN. I wanted to serve it locally.

  1. I went to Skypack to get their browser-optimized packaged version of Dayjs: https://cdn.skypack.dev/dayjs and saved the content of that to /app/assets/javascripts/libraries/dayjs/dayjs.js.erb (note .erb). That file looked like this on Skypack.

    export * from '/-/dayjs@v1.10.4-MoS2QVkxh1TZYPgJA5zq/dist=es2020,mode=imports/optimized/dayjs.js';
    export {default} from '/-/dayjs@v1.10.4-MoS2QVkxh1TZYPgJA5zq/dist=es2020,mode=imports/optimized/dayjs.js';

    which I changed to the following, using asset_path:

    export * from '<%= asset_path "libraries/dayjs/dayjs.export.js" %>';
    export {default} from '<%= asset_path "libraries/dayjs/dayjs.export.js" %>';
  2. That originally referenced https://cdn.skypack.dev//-/dayjs@v1.10.4-MoS2QVkxh1TZYPgJA5zq/dist=es2020,mode=imports/optimized/dayjs.js file, I saved unchanged to /app/assets/javascripts/libraries/dayjs/dayjs.export.js

  3. In my importmap.json.erb I added:

     {
       "imports": { 
         "turbo": "<%= asset_path "turbo" %>",
         <%= importmap_list_with_stimulus_from "app/assets/javascripts/controllers", "app/assets/javascripts/libraries" %>,
    +    "dayjs": "<%= asset_path "libraries/dayjs/dayjs.js" %>"
       }
     }
  4. In my Stimulus controller, I added:

      import { Controller } from "stimulus"
    + import dayjs from 'dayjs';

Thanks for a prod that led me in the right direction 🥳

@turgs turgs closed this as completed Feb 28, 2021
@turgs
Copy link
Author

turgs commented Mar 1, 2021

Better yet, I've just realised that I don't need to do this required "date logic" and calculations in javascript anymore, because I should now be able to use a turbo frame and keep the logic in Rails 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants