ruby-on-railsruby-on-rails-7import-mapstinymce-6

Rails engine importmap Uncaught ReferenceError: tinymce is not defined


I am using importmap with a downloaded version of tinymce in a rails 7.1 engine. I am failing to get the editor to display and the browser console shows the following error

    Uncaught ReferenceError: tinymce is not defined
    <anonymous> http://localhost:3000/admin_dashboard/page_maintenance/something-new/edit:128
edit:128:11

I have pinned the local tinymce javascript file in importmap.rb and my importmap.rb has the following code

pin "ccs_cms/custom_page/application"

#pin "ccs_cms/custom_page/sortable"
pin "ccs_cms/custom_page/nested_fields/addFields"
pin "ccs_cms/custom_page/nested_fields/removeFields"
#pin "jquery", to: "jquery-3.6.0.min.js"
#pin "jquery-ui", to: "jquery-ui.min.js"
pin "ccs_cms/custom_page/tinymce/tinymce.min"

jquery and jquery are commented out as they also fail with a $ is not defined error. the add and remove fields javascript functionality works as expected in the same view so I know I have the importmap configuration correctly setup

My view has the following code

<% content_for :admin_import_maps do %>
  <%#= javascript_import_module_tag 'ccs_cms/custom_page/application' %>
  <%= javascript_import_module_tag 'ccs_cms/custom_page/tinymce/tinymce.min' %>
  <%= javascript_import_module_tag 'ccs_cms/custom_page/nested_fields/addFields' %>
  <%= javascript_import_module_tag 'ccs_cms/custom_page/nested_fields/removeFields' %>
<% end %>

This generates the following head html

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Admin dashboard</title>
  <meta name="csrf-param" content="authenticity_token">
<meta name="csrf-token" content="SXef8TuH8fgvCsoc1jkl2molUHoNIU50nKKrTC484SCWH_F2y54y1zEaSxNdHz5g-NJdWlv5Xm8pSKki-zmmuQ">
  
  <script type="importmap" data-turbo-track="reload">{
  "imports": {
    "ccs_cms/custom_page/application": "/assets/ccs_cms/custom_page/application-99668eaf7a77ddf69599e88d13e2ec298da4543391fb6625b3a97c3da1c19e5d.js",
    "ccs_cms/custom_page/nested_fields/addFields": "/assets/ccs_cms/custom_page/nested_fields/addFields-1a38ed3d39bbaa916c45bc7718670854ac99e783836600003446abdd2bffc4b7.js",
    "ccs_cms/custom_page/nested_fields/removeFields": "/assets/ccs_cms/custom_page/nested_fields/removeFields-62e34f17e460cd64712cf6e34f576e56147ec1711d5bf13e0b5eecf86ce5b491.js",
    "ccs_cms/custom_page/tinymce/tinymce.min": "/assets/ccs_cms/custom_page/tinymce/tinymce.min-4ee986c9ca92871e240ef08a8b307c58edd8f9794494fa88553f26de181d98e0.js"
  }
}</script>

<script src="/assets/es-module-shims.min-4ca9b3dd5e434131e3bb4b0c1d7dff3bfd4035672a5086deec6f73979a49be73.js" async="async" data-turbo-track="reload"></script>
<script type="module">import "application"</script>
    <script type="module">import "ccs_cms/custom_page/tinymce/tinymce.min"</script>
  <script type="module">import "ccs_cms/custom_page/nested_fields/addFields"</script>
  
  </head>

This looks to me like the importmap is being included for tinymce.min.js file and the module is being included also

The view partial that should be displaying the tinymce editor has the following code

  <section>
    <fieldset>
      <legend> Page Section </legend>
      <%= form.hidden_field :_destroy %>

      <fieldset>
        <legend> Menu </legend>

        <div class="cms-admin-field">
          <%= form.label :content %>:
          <%= form.text_area :content %>
        </div>

        <script>
          tinymce.init({
            selector: 'textarea',
            plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount checklist mediaembed casechange export formatpainter pageembed linkchecker a11ychecker tinymcespellchecker permanentpen powerpaste advtable advcode editimage tinycomments tableofcontents footnotes mergetags autocorrect typography inlinecss',
            toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat',
            tinycomments_mode: 'embedded',
            tinycomments_author: 'Author name',
            mergetags_list: [
              { value: 'First.Name', title: 'First Name' },
              { value: 'Email', title: 'Email' },
            ],
          });
        </script>

This generates the following html

<section>
    <fieldset>
      <legend> Page Section </legend>
      <input autocomplete="off" type="hidden" value="false" name="menu_item[page_sections_attributes][0][_destroy]" id="menu_item_page_sections_attributes_0__destroy">

      <fieldset>
        <legend> Menu </legend>

        <div class="cms-admin-field">
          <label for="menu_item_page_sections_attributes_0_content">Content</label>:
          <textarea name="menu_item[page_sections_attributes][0][content]" id="menu_item_page_sections_attributes_0_content"></textarea>
        </div>

        <script>
          tinymce.init({
            selector: 'textarea',
            plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount checklist mediaembed casechange export formatpainter pageembed linkchecker a11ychecker tinymcespellchecker permanentpen powerpaste advtable advcode editimage tinycomments tableofcontents footnotes mergetags autocorrect typography inlinecss',
            toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat',
            tinycomments_mode: 'embedded',
            tinycomments_author: 'Author name',
            mergetags_list: [
              { value: 'First.Name', title: 'First Name' },
              { value: 'Email', title: 'Email' },
            ],
          });
        </script>


      <div class="cms-admin-field">
        <label for="menu_item_page_sections_attributes_0_collapsed_header_text">Collapsed header text</label>:
        <input editor="template classic type classic" type="text" value="" name="menu_item[page_sections_attributes][0][collapsed_header_text]" id="menu_item_page_sections_attributes_0_collapsed_header_text">
      </div>
      <div class="cms-admin-field">
        <label for="menu_item_page_sections_attributes_0_include_contact_form">Include contact form</label>:
        <input name="menu_item[page_sections_attributes][0][include_contact_form]" type="hidden" value="0" autocomplete="off"><input type="checkbox" value="1" name="menu_item[page_sections_attributes][0][include_contact_form]" id="menu_item_page_sections_attributes_0_include_contact_form">
      </div>
      <div class="cms-admin-field">
        <label for="menu_item_page_sections_attributes_0_collapsible">Collapsible</label>:
        <input name="menu_item[page_sections_attributes][0][collapsible]" type="hidden" value="0" autocomplete="off"><input type="checkbox" value="1" name="menu_item[page_sections_attributes][0][collapsible]" id="menu_item_page_sections_attributes_0_collapsible">
      </div>
      <div class="cms-admin-field">
        <label for="menu_item_page_sections_attributes_0_has_borders">Has borders</label>:
        <input name="menu_item[page_sections_attributes][0][has_borders]" type="hidden" value="0" autocomplete="off"><input type="checkbox" value="1" name="menu_item[page_sections_attributes][0][has_borders]" id="menu_item_page_sections_attributes_0_has_borders">
      </div>
      <div class="cms-admin-field">
        <label for="menu_item_page_sections_attributes_0_full_width">Full width</label>:
        <input name="menu_item[page_sections_attributes][0][full_width]" type="hidden" value="0" autocomplete="off"><input type="checkbox" value="1" name="menu_item[page_sections_attributes][0][full_width]" id="menu_item_page_sections_attributes_0_full_width">
      </div>
      <div>
        <a class="remove_fields" href="#">Remove</a>
      </div>
    </fieldset>
  </fieldset></section>

The tinymce.init line is the cause of the error.

Obviously I would like to move the init script to a .js file and import that but keeping things inline for now until I can get this working. What am I missing please?


Solution

  • Missing type="module":

    <script type="module">
      import "https://cdn.tiny.cloud/1/no-api-key/tinymce/6.7.0-30/tinymce.js"
    </script>
    
    <script type="module">
      console.log(tinymce)
    </script>
    

    Regular script tags are executed first, and tinymce is not yet imported, module scripts are deferred and run later:

    <script type="module">
      console.log("second")
    </script>
    
    <script>
      console.log("first")
    </script>