excid3 / esbuild-rails

Esbuild Rails plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for bun package manager

navidemad opened this issue · comments

Hello, firstly thanks for your plugin.
Recently bun new package manager has been out, apparently faster than esbuild and its plugin interface is based on esbuild, but for some reason it does not works properly. For your information, there is a library called unplugin that allow to make a plugin works for multiple package manager : unjs/unplugin#329

Other links:
https://bun.sh/docs/runtime/plugins
https://dev.to/jacobandrewsky/building-universal-jsts-plugins-with-unplugin-5328
https://bun.sh/docs/bundler/plugins
https://bun.sh/docs/bundler/vs-esbuild

I can confirm it does not work at the moment, here is the code I used and the error I got :

import rails from 'esbuild-rails'

const result = await Bun.build({
  entrypoints: [
    'app/javascript/application.js'
  ],
  naming: {
    chunk: '[name]-[hash].digested'
  },
  splitting: true,
  format: 'esm',
  outdir: 'app/assets/builds',
  plugins: [
    rails()
  ]
})
error: undefined is not an object (evaluating 'args.pluginData.path')
/path/to/my/project/undefined/**/*_controller.ts:1:0 0

Might look into it if anyone has pointers

I try to customize it the plugin. In bun, there is no resolveDir and neither pluginData.
My workflow of testing is:

CLI:
  rails new bun-plugin-rails-app --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-job --skip-active-storage --skip-action-cable --skip-jbuilder --skip-test --skip-system-test -j bun --main
  cd bun-plugin-rails-app

Change in Gemfile:
  gem "jsbundling-rails", github: "rails/jsbundling-rails"

CLI:
  bundle update
  rails javascript:install:bun
  bundle update
  mkdir -p app/javascript/public
  echo 'console.log(new Date().toTimeString());' >> app/javascript/public/test.js
  echo 'import "./**/*.js";' >> app/javascript/application.js
  rails g controller pages home
  bin/dev
  open http://localhost:3000/pages/home
import path from 'path';
import fg from 'fast-glob';

// Transform filenames to controller names
// [ './admin/hello_world_controller.js', ... ]
// [ 'admin--hello-world', ... ]
function convertFilenameToControllerName(filename) {
  return filename
    .replace(/^\.\//, "") // Remove ./ prefix
    .replace(/_controller.[j|t]s$/, "") // Strip _controller.js extension
    .replace(/\//g, "--") // Replace folders with -- namespaces
    .replace(/_/g, '-') //
}

// This plugin adds support for globs like "./**/*" to import an entire directory
// We can use this to import arbitrary files or Stimulus controllers and ActionCable channels
const railsPlugin = (options = { matcher: /.+\..+/ }) => {
  const resolveMap = new Map();
  return {
    name: 'rails',
    setup(build) {
      build.onResolve({ filter: /\*/ }, async (args) => {
        console.log("onResolve");
        console.log(args);
        resolveMap.set(args.importer + args.path, {
          path: args.path,
          resolveDir: path.dirname(args.importer),
        })
        return {
          path: args.importer + args.path,
          namespace: 'bun-rails',
        };
      });

      build.onLoad({ filter: /.*/, namespace: 'bun-rails' }, async (args) => {
        const resolveData = resolveMap.get(args.path);
        console.log(`Searching for '${resolveData.path}' in ${resolveData.resolveDir}`);
        let files = await fg(resolveData.path, { cwd: resolveData.resolveDir });
        files = files.sort().filter(p => options.matcher.test(p));
        files = files.map((filepath) => path.relative(resolveData.resolveDir, filepath));
        console.log(files);
        const controllerNames = files.map(convertFilenameToControllerName);

        const importerCode = `
          ${files
            .map((module, index) => `import * as module${index} from './${module}'`)
            .join(';')}
          const modules = [${controllerNames
            .map((module, index) => `{name: '${module}', module: module${index}, filename: '${files[index]}'}`)
            .join(',')}]
          export default modules;
        `;

        return { contents: importerCode };
      });
    },
  };
};

There is some logs remaining but if it can help you find a long term solution and better one.

Sorry about this. We will take a look on our end about adding these missing options to Bun.