Loading…
Kind of curious about this myself. I've been looking into sprockets-es6 and I have no idea how to bridge the module declarations with my work.
Also really interested.
I'm also interested in this.
Let's pretend I didn't understand half of the words you used in this issue. Also let's pretend that the original author of sprockets isn't here anymore and i'll likely have to work with whatever solution we decide to go with forwards. Let's be patient and go slowly.
What's babel?
Babel is a compiler for writing next generation JavaScript.
Okay. That seems like a thing we should want to support.
What is a common js require?
Looks like it's a way to import explicit functions from http://wiki.commonjs.org/wiki/Modules/1.1
What's a ES6 module declarations?
Looks like it's a way of importing module like behavior http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples.
We already have a babel processor. It looks like it currently supports es6
def test_compile_es6_features_to_es5
input = {
content_type: 'application/ecmascript-6',
data: "const square = (n) => n * n",
metadata: {},
load_path: File.expand_path("../fixtures", __FILE__),
filename: File.expand_path("../fixtures/mod.es6", __FILE__),
cache: Sprockets::Cache.new
}
assert js = Sprockets::BabelProcessor.call(input)[:data]
assert_match(/var square/, js)
assert_match(/function/, js)
end
The test suite uses babel-transpiler
from https://github.com/babel/ruby-babel-transpiler. How does sprockets know to convert es6 files?
# Babel, TheFuture™ is now
require 'sprockets/babel_processor'
register_mime_type 'application/ecmascript-6', extensions: ['.es6'], charset: :unicode
register_transformer 'application/ecmascript-6', 'application/javascript', BabelProcessor
register_preprocessor 'application/ecmascript-6', DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])
It looks like sprockets gets its ES6 support directly from babel. How are commonJS requires implemented? Is it a different file extension & mime type or is it some other layer on top of es6? If it's a file extension then once the babel-transpiler supports commonjs then we can register that in the same way. There will probably be some plumbing needed in the processor itself.
We would like to use CommonJS export/require with CoffeeScript.
Currently we're getting the job done with the Browserify-Rails gem. It works, but is slow as heck, and the setup is complex. IMHO it would be a big improvement for Rails if CommonJS was incorporated directly into sprockets.
I can't imagine building any JavaScript front-end these days without CommonJS - I believe it should be part of Sprockets.
Babel does not implement common js requires itself. All it does it rewrite ES6 imports (i.e. import foo from 'foo'
) to common js requires (i.e. var foo = require('foo')
). There are more examples in the docs. Tools like webpack include a minimal runtime in the final js output which defines a require
function, and concatenate the contents of all js files inside an array to allow lookup via this require function.
Well that is the thing - Sprockets does not provide a loader, and it seems that this is something that pretty much anyone would expect in a modern setup. And that loader should work both with precompiled assets and expando assets. I know it is a tall order, but...
Sprockets does not provide a loader,
Can you give me more info, what exactly is a "loader", this term has a sprockets specific context
# The loader phase takes a asset URI location and returns a constructed Asset
# object.
Something that could help an implementer could be a PR with a failing test. Here's an example of an es6 test https://github.com/rails/sprockets/blob/7b913165d54bef952b8f83509e731a90987321bb/test/test_environment.rb#L268-L272
You would need to add your own asset.
@opal would benefit from a loader too, currently we monkeypatch javascript_invlude_tag
to append the final load statement that will bootstrap the app.
I looked into that in the past and I suspect sprockets pipelines can be used for something like that.
https://github.com/opal/opal-rails/blob/master/app/helpers/opal_helper.rb
@scheems a Loader would be a 3rd party JavaScript library responsible for polyfilling the import
/require
features from ES6 that aren't currently supported by browsers. The Babel transformer can transpile these keywords to plain JavaScript code but the application still needs to provide the mechanism to load the JavaScript files as expected through loader like almond.js for AMD modules or System.js.
Folks using sprockets 3 and the sprockets-es6
plugin can reconfigure the ES6
transformer to use a specific module format supported by Babel on their apps with something like the following:
Rails.application.config.assets.configure do |env|
es6amd = Sprockets::ES6.new('modules' => 'amd', 'moduleIds' => true)
# Replace the default transformer to transpile each `.es6` file with `define`
# and `require` from the AMD spec.
# Just be sure to add `almond.js` to the application and
# require it before requiring other assets on `application.js`
env.register_transformer 'text/ecmascript-6', 'application/javascript', es6amd
end
Ideally, Sprockets could choose a module format by default (like system
), and ship with a Module Loader polyfill for the same format so developers can use ES6 modules without the extra steps of recofinguring the transformer or adding these 3rd party libraries manually, but that could be something done by an extra plugin rather than live in this codebase.
Hope this helps to shed some light on some of the terms from the ES6 world here I'm using this setup on my current project and I believe that some other users of sprockets-es6 might have done a similar setup on their apps.
@lucasmazza Thanks so much. Exactly what I needed! However the syntax is thus:
Rails.application.config.assets.configure do |env|
es6amd = Sprockets::BabelProcessor.new('modules' => 'amd', 'moduleIds' => true)
# Replace the default transformer to transpile each `.es6` file with `define`
# and `require` from the AMD spec.
# Just be sure to add `almond.js` to the application and
# require it before requiring other assets on `application.js`
env.register_transformer 'application/ecmascript-6', 'application/javascript', es6amd
end
Currently Babel is switched to replace ES6 module declarations with CommonJS requires, whereas Sprockets does not provide a runtime to handle those requires.
Is there some roadmap as to how modules are going to be wired into Sprockets, or does it have to be handled by some module you have to BYO?