Search code examples
ruby-on-railschart.jsimport-maps

Get Chart.js to work with ImportMap in Rails 7


I tried:

./bin/importmap pin chart.js

which added this to config/importmap.rb

pin "chart.js", to: "https://ga.jspm.io/npm:[email protected]/dist/chart.mjs"

In application.js I added:

import 'chart.js'

When I try to create a new Chart I get "Chart is not defined".

If I try

import Chart from 'chart.js'

I get "The requested module 'chart.js' does not provide an export named 'default'"

import Chart from 'chart.js/auto' 

says "Failed to resolve module specifier 'chart.js/auto'"


Solution

  • I had the same struggle this weekend and kept happening upon this article, so posting my solution here.

    A couple things of note:

    1. Chart.js seems to have some hardcoded accessory files that aren't registered as dependencies in the CDN. For example, mine kept 404ing on c1719c72.js and chunks/helpers.segment.js. For this reason, it works better if you don't use the --download flag when running bin/importmap pin. Credit to this article: Using chart.js with importmaps in rail 7.
    2. Importing Chart from chart.js requires a little magic from here: Chart.js - Where do I find which components should be registered?. Specifically, lines 3-4 of barchart_controller.js below.

    Here's a summary of the file contents that worked for me on a fairly plain Rails 7 build with importmaps:

    config/importmap.rb - Note: Running bin/importmap pin chart.js should pull in one dependency (@kurkle/color). Be sure to skip --download, or you're in for a world of pain.

    # Pin npm packages by running ./bin/importmap
    
    pin "application", preload: true
    pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
    pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
    pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
    pin_all_from "app/javascript/controllers", under: "controllers"
    
    pin "chart.js", to: "https://ga.jspm.io/npm:[email protected]/dist/chart.js"
    pin "@kurkle/color", to: "https://ga.jspm.io/npm:@kurkle/[email protected]/dist/color.esm.js"
    

    app/javascript/application.js

    // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
    import "@hotwired/turbo-rails"
    import "controllers"
    
    import "chart.js"
    

    app/javascript/controllers/barchart_controller.js

    import {Controller} from "@hotwired/stimulus"
    
    import { Chart, registerables } from "chart.js";
    Chart.register(...registerables);
    
    export default class extends Controller {
        static targets = ['myChart'];
    
        canvasContext() {
            return this.myChartTarget.getContext('2d');
        }
    
        connect() {
            new Chart(this.canvasContext(), {
                type: 'bar',
                data: {
                    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
                    datasets: [{
                        label: '# of Votes',
                        data: [12, 19, 3, 5, 2, 3],
                        backgroundColor: [
                            'rgba(255, 99, 132, 0.2)',
                            'rgba(54, 162, 235, 0.2)',
                            'rgba(255, 206, 86, 0.2)',
                            'rgba(75, 192, 192, 0.2)',
                            'rgba(153, 102, 255, 0.2)',
                            'rgba(255, 159, 64, 0.2)'
                        ],
                        borderColor: [
                            'rgba(255, 99, 132, 1)',
                            'rgba(54, 162, 235, 1)',
                            'rgba(255, 206, 86, 1)',
                            'rgba(75, 192, 192, 1)',
                            'rgba(153, 102, 255, 1)',
                            'rgba(255, 159, 64, 1)'
                        ],
                        borderWidth: 1
                    }]
                },
                options: {
                    scales: {
                        y: {
                            beginAtZero: true
                        }
                    }
                }
            });
        }
    }
    

    Content from the div in my model's app/views/widgets/show.html.erb

    <div data-controller="barchart">
      <canvas id="bar-chart" data-barchart-target="myChart" width="800" height="450"></canvas>
    </div>
    

    Don't forget to rebuild assets (bin/rails assets:precompile).