All Projects → rmacklin → sprockets-bumble_d

rmacklin / sprockets-bumble_d

Licence: MIT license
Sprockets plugin to transpile modern javascript using Babel, useful while migrating to ES6 modules

Programming Languages

ruby
36898 projects - #4 most used programming language
HTML
75241 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to sprockets-bumble d

Sprockets-PHP
Sprockets for PHP
Stars: ✭ 50 (+56.25%)
Mutual labels:  sprockets, asset-pipeline
sprockets-standalone
Rack task library for using Sprockets standalone.
Stars: ✭ 15 (-53.12%)
Mutual labels:  sprockets, asset-pipeline
babel-plugin-react-directives
A babel plugin that provides some directives for react(JSX), similar to directives of vue.
Stars: ✭ 80 (+150%)
Mutual labels:  babel-plugin
typescript-api-starter
🔰 Starter for Node.js express API in Typescript 🚀
Stars: ✭ 72 (+125%)
Mutual labels:  migration
porter
Export legacy forums into a format Vanilla Forums can import.
Stars: ✭ 39 (+21.88%)
Mutual labels:  migration
babel-plugin-transform-react-qa-classes
Add component's name in `data-qa` attributes to React Components
Stars: ✭ 41 (+28.13%)
Mutual labels:  babel-plugin
mongock
Lightweight Java based migration tool
Stars: ✭ 357 (+1015.63%)
Mutual labels:  migration
laminas-dependency-plugin
Replace zendframework and zfcampus packages with their Laminas Project equivalents.
Stars: ✭ 32 (+0%)
Mutual labels:  migration
go-echo-boilerplate
The fastest way to build a restful API with golang and echo framework. Includes common required features for modern web applications. A boilerplate project with golang and Echo.
Stars: ✭ 53 (+65.63%)
Mutual labels:  migration
butterfly
Application transformation tool
Stars: ✭ 35 (+9.38%)
Mutual labels:  migration
babel-plugin-object-styles-to-template
Babel plugin to transpile object styles to template literal
Stars: ✭ 33 (+3.13%)
Mutual labels:  babel-plugin
amazon-s3-data-replication-hub-plugin
The Amazon S3 Transfer Plugin for Data Transfer Hub(https://github.com/awslabs/data-transfer-hub). Transfer objects from S3(in other partition), Alibaba Cloud OSS, Tencent COS, Qiniu Kodo into Amazon S3.
Stars: ✭ 32 (+0%)
Mutual labels:  migration
tm-tools
some useful tools for tendermint blockstore.db or state.db
Stars: ✭ 14 (-56.25%)
Mutual labels:  migration
flickr to google photos migration
A tool for migrating your photo library from Flickr to Google Photos
Stars: ✭ 39 (+21.88%)
Mutual labels:  migration
babel-plugin-transform-amd-to-commonjs
✨ Babel plugin that transforms AMD to CommonJS
Stars: ✭ 44 (+37.5%)
Mutual labels:  babel-plugin
Ramses
The Rx Asset Management System for motion picture production
Stars: ✭ 48 (+50%)
Mutual labels:  asset-pipeline
babel-plugin-console-source
Add the file name and line numbers to all console logs.
Stars: ✭ 38 (+18.75%)
Mutual labels:  babel-plugin
great-migration
Copy objects from Rackspace to S3
Stars: ✭ 15 (-53.12%)
Mutual labels:  migration
migration-tool
Automated script to migrate from Directus v8 to Directus v9
Stars: ✭ 21 (-34.37%)
Mutual labels:  migration
schema-builder
Laravel/Lumen schema builder & migration generator
Stars: ✭ 51 (+59.38%)
Mutual labels:  migration

Sprockets::BumbleD

This gem provides a plugin for Sprockets that enables you to transpile modern javascript using Babel.

A primary use case for this gem is to incrementally migrate your Sprockets-powered javascript codebase to ES6 modules. This works by transforming them to UMD modules that preserve your existing global variable references (hence the name: Babel + UMD = BumbleD). Once an entire subtree of your javascript module tree is written in ES6 modules, this frees you up to bundle that javascript using a more modern tool (e.g. rollup or webpack).

That said, this gem can be used for general purpose babel transpilation within the Sprockets pipeline.

Background

ES6 modules are the new standard. The syntax is great: it's concise and straightforward, and the static and explicit nature of import and export statements make your code a complete spec of its dependencies and how to resolve them. This means that moving to ES6 modules also makes moving away from Sprockets //= require directives for javascript bundling (and Sprockets in general) much easier.

But when faced with a large legacy codebase, it's not feasible to convert everything to ES6 modules at once. Thus, the goal is to be able to convert module-by-module from explicitly exporting a global variable (and depending on other modules' global variables) to following the ES6 module format, which we'll then transpile to UMD that is compatible with non-converted code (e.g. existing UMD modules and plain old global-dependent scripts).

Sprockets::BumbleD accomplishes this goal by providing a Sprockets transformer that acts on .es6 files (this file extension is configurable). These files are transpiled by Babel and the ES2015 -> UMD modules transform plugin, preserving any globals that you've registered.

Setup

Installation

  1. Add gem 'sprockets-bumble_d' to your Gemfile (or add a gemspec dependency to an inline engine in your app) and run bundle install.
  2. Run npm install --save @babel/core @babel/plugin-external-helpers @babel/plugin-transform-modules-umd @babel/preset-env to install the modules for the default babel config. If you want to customize the babel options, install any additional plugins and presets you want.
  3. Generate the external helpers and //= require them in at the beginning of your application manifest or pull them in with a separate script tag. This step is of course unnecessary if you won't be using the external-helpers plugin, but it's highly recommended that you do (to avoid inlining them everywhere, which unnecessarily bloats the bundle sent to the browser).

Basic configuration

In config/application.rb:

extend Sprockets::BumbleD::DSL

configure_sprockets_bumble_d do |config|
  config.babel_config_version = 1
end

If you are not using Rails, you must also configure the root_dir (see below).

Customizing the root_dir

Sprockets::BumbleD needs to know the directory from which node modules are to be resolved (typically, wherever your package.json resides). If you're using Rails, this defaults to Rails.root.to_s. If you are not using Rails, or if your node_modules folder is not inside Rails.root, you must configure the root_dir setting! For example, if you are configuring Sprockets::BumbleD in the file config/application.rb and your package.json is located in the parent directory, use:

configure_sprockets_bumble_d do |config|
  config.root_dir = File.expand_path('..', __dir__)
  config.babel_config_version = 1
end

If it's in a specific subdirectory, specify that directory instead. Sprockets::BumbleD doesn't care, as long as its node require statements will resolve from that directory.

Customizing your babel options

By default you get @babel/preset-env, @babel/plugin-external-helpers, and @babel/plugin-transform-modules-umd. If you want to customize this with different plugins and presets, specify them in the configure_sprockets_bumble_d block with the babel_options setting. Note that (because it's central to the purpose of this gem) @babel/plugin-transform-modules-umd is included for you (unless you set transform_to_umd to false) and configured to use the registered globals, so this plugin does not need to be specified when you override the default plugins.

For example:

configure_sprockets_bumble_d do |config|
  config.babel_config_version = 2
  config.babel_options = {
    presets: ['@babel/preset-env', '@babel/preset-react'],
    plugins: ['@babel/plugin-external-helpers', 'custom-plugin']
  }
end

You can specify any options that are allowed in a .babelrc file.

Customizing the file extension

By default the Sprockets transformer is registered to act on .es6 files. This is configurable:

configure_sprockets_bumble_d do |config|
  config.babel_config_version = 1
  config.file_extension = '.babel'
end

The babel_config_version setting

What's this mysterious babel_config_version we're setting in the previous examples? Good question. Essentially this is intended to be a value that translates to the composite version of @babel/core and each babel preset and plugin in your application. It's used to expire the cache for compiled assets: since different versions of babel and its plugins can result in a different transpiled output, we want to be able to invalidate the cache whenever we change our babel configuration. So, when you upgrade @babel/core or you add/remove/upgrade a babel plugin or preset, you'd increment this version which will cause the Sprockets transformer's cache key to change.

Philosophy

You should own your babel setup. We want to be able to use the latest versions of babel and its plugins as soon as they're available, so this gem doesn't vendor any node modules - it's up to the application to provide those to the gem. This is what the root_dir config is for. It's also why the babel_config_version setting exists.

Registering globals

@babel/plugin-transform-modules-umd includes an exactGlobals option that lets you specify exactly how to transpile any import statements into the global reference it should resolve to. It also lets you specify what global should be exported by an ES6 module in the resultant UMD output. (A complete description is available in babel PR #3534.)

In config/application.rb, after extend Sprockets::BumbleD::DSL:

register_umd_globals :my_app,
  'my/great/thing' => 'MyGreatThing',
  'her/cool/tool'  => 'herCoolTool'

Doing this will allow:

import GreatThing from 'my/great/thing';

to be transpiled to:

factory(/* ... */ global.MyGreatThing);

in the globals branch of the transpiled UMD output. Similarly, the above map also specifies that the exports of the ES6 module her/cool/tool will be assigned to the herCoolTool global.

That is, registering these globals provides both:

  • a way to depend on existing globals in ES6 modules
  • a way to declare the global an ES6 module should export, to be used in existing UMD modules or direct global references

As a corollary, if you are writing a new ES6 module that is only used by other ES6 modules, you would not need to register a global for that module's export.

Exported globals can also be nested objects and the transform will properly handle creating the necessary prerequisite assignments. For example with this registration:

register_umd_globals :my_app,
  'her/cool/tool' => 'Her.Cool.Tool'

the compiled her/cool/tool module will contain:

global.Her = global.Her || {};
global.Her.Cool = global.Her.Cool || {};
global.Her.Cool.Tool = mod.exports;

Inline Rails engines

If you have a large application, you may have split it into multiple inline rails engines (as described in this talk). Inline engines with their own assets should own the registration of globals for these assets. This is supported in Sprockets::BumbleD:

in some_engine/engine.rb:

extend Sprockets::BumbleD::DSL

register_umd_globals :some_engine,
  'some_namespace/first_module'  => 'SomeNamespace.firstModule',
  'some_namespace/second_module' => 'SomeNamespace.secondModule',
  'another_thing/mod'            => 'anotherModule'

Since module globals should only be registered in the engine (or top level application) where the module lives, register_umd_globals will raise Sprockets::BumbleD::ConflictingGlobalRegistrationError if a module is registered a second time. Of course, this still can't prevent you from registering globals (that had not already been registered) in the wrong engine.

Reminder about Rails reloading

As with any config changes, updates to the globals registry are not reloaded automatically; you must restart your server for the changes to take effect.

Do I have to transpile to UMD modules?

No, you can transpile to other module formats (e.g. AMD). You'd just be using less of this gem's API surface area 1. You can set transform_to_umd to false in your configure_sprockets_bumble_d block, and override the default plugins to use a different module transform. For example if you're using an AMD loader like almond, you could configure modules to be transpiled to AMD like so:

configure_sprockets_bumble_d do |config|
  config.root_dir = File.expand_path('..', __dir__)
  config.babel_config_version = 1
  config.transform_to_umd = false
  config.babel_options = {
    presets: ['@babel/preset-env'],
    plugins: ['@babel/plugin-external-helpers', '@babel/plugin-transform-modules-amd']
  }
end

You can reference the 5.0_amd test app which demonstrates this in a full application.

1 Of course if you're doing this, you wouldn't ever call register_umd_globals

Similar projects

  • babel-schmooze-sprockets - This takes a similar approach, but it requires Sprockets 4 (which is still in beta), and it doesn't offer a way to register globals within inline engines. Additionally, it diverges in philosophy by vendoring some node_modules.
  • sprockets-es6 - This was the common solution for ES6 transpilation within Sprockets for a while, but it takes a very different approach. Instead of relying on node and the npm ecosystem, it uses ruby-babel-transpiler, which is stuck on babel 5. This means you cannot configure custom babel plugins (which means you can't use exactGlobals to specify what it should transform globals to in the UMD modules transform).
  • sprockets 4 - This takes the same approach as sprockets-es6 so it suffers from the same limitations as sprockets-es6
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].