I'm starting to get my head around the new import maps functionality in rails 7. It seems there are a lot of advantages of using this functionality.
It seems however if I need a transpile step (eg JSX) that I need a js bundling solution. It's not clear to me if that means I also must then NOT use import maps, or have any of it's benefits?
Can someone help me understand whether these can be used at the same time or not?
CodePudding user response:
Importmaps work with import
statements, esbuild will remove all imports. It doesn't really make sense to use importmaps on top of esbuild. However, you can use them in parallel so to speak. Just create two javascript entry files, one processed by esbuild and the other left untouched for use with importmaps.
<%= javascript_importmap_tags "application_importmap" %>
<%= javascript_include_tag "application_esbuild", defer: true %>
If you have import
statements in application.js and you use esbuild, it will smoosh all the imports together into one file, plus transpile, compile, and whatever else you set it up to do. There are no import
statements left after that and you get the familiar gobbledygook bundle:
// application.js
(() => {
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
...
If you use importmaps, there is no preprocessing of any kind and all the import
statements stay untouched. Actual importing is delegated to the browser. This is where importmaps do the work, application.js and other files are untouched:
// application.js
import "@hotwired/turbo-rails";
Importmaps tell the browser where to find @hotwired/turbo-rails, for example. Because it is not a URL browser can fetch it has to be mapped to a URL. This is why you're making those pins. They take care of making a mapping to a relative or remote URL. Relative URLs are handled by sprockets and automatically updated on file changes.
<script type="importmap" data-turbo-track="reload">{
"imports": {
"@hotwired/turbo-rails": "/assets/turbo-5605bff731621f9ca32b71f5270be7faa9ccb0c7c810187880b97e74175d85e2.js",
"application": "/assets/application-0fe7d3d5e7e66b4e14e543d5e9caa2c8eaabde6653ad2d873c4ddc3dea81f0fd.js"
}
}</script>
If your application.js is processed by esbuild there is nothing left to do for importmaps.
Maybe you could just transpile jsx and leave imports untouched, but that feels like an overkill of a set up.
To keep it simple, pick one or the other: stick to basic javascript and use importmaps, otherwise use esbuild.