canvas-lms/lib/tasks/js.rake

239 lines
8.2 KiB
Ruby

require 'json'
require_relative "../../config/initializers/webpack"
namespace :js do
# ---------------- META TASKS ----------------
# (add functionality as a separate task below)
desc "Generates compiled coffeescript, handlebars templates and plugin extensions"
task :generate do
require 'config/initializers/client_app_symlinks'
require 'config/initializers/plugin_symlinks'
Rake::Task['js:clean'].invoke
Rake::Task['js:build_client_apps'].invoke
threads = []
threads << Thread.new do
puts "--> Generating plugin extensions"
extensions_time = Benchmark.realtime { Rake::Task['js:generate_extensions'].invoke }
puts "--> Generating plugin extensions finished in #{extensions_time}"
end
threads << Thread.new do
puts "--> Compiling React JSX"
jsx_time = Benchmark.realtime { Rake::Task['js:jsx'].invoke }
puts "--> Compiling React JSX finished in #{jsx_time}"
end
threads << Thread.new do
puts "--> Pre-compiling handlebars templates"
handlebars_time = Benchmark.realtime { Rake::Task['jst:compile'].invoke }
puts "--> Pre-compiling handlebars templates finished in #{handlebars_time}"
end
threads << Thread.new do
puts "--> Pre-compiling ember handlebars templates"
ember_handlebars_time = Benchmark.realtime { Rake::Task['jst:ember'].invoke }
puts "--> Pre-compiling ember handlebars templates finished in #{ember_handlebars_time}"
end
# can't be in own thread, needs to happen before coffeescript
puts "--> Creating ember app bundles"
bundle_time = Benchmark.realtime { Rake::Task['js:bundle_ember_apps'].invoke }
puts "--> Creating ember app bundles finished in #{bundle_time}"
threads << Thread.new do
coffee_time = Benchmark.realtime do
Rake::Task['js:coffee'].invoke
end
puts "--> Compiling CoffeeScript finished in #{coffee_time}"
end
threads.each(&:join)
end
desc "Optimize and build js for production"
task :build do
Rake::Task['js:rjs_config'].invoke
puts "--> Concatenating JavaScript bundles with r.js"
time = Benchmark.realtime { Rake::Task['js:rjs_concat'].invoke }
puts "--> Concatenated JavaScript bundles in #{time}"
unless ENV["JS_BUILD_NO_UGLIFY"]
puts "--> Compressing JavaScript with UglifyJS"
time = Benchmark.realtime { Rake::Task['js:compress'].invoke }
puts "--> Compressed JavaScript in #{time}"
end
end
# --- TASKS ---
desc "Generates plugin extension modules"
task :generate_extensions do
require 'canvas/require_js/plugin_extension'
Canvas::RequireJs::PluginExtension.generate_all
end
desc "Build client_apps"
task :build_client_apps do
require 'config/initializers/client_app_symlinks'
Dir.glob('./client_apps/*/').each do |app_dir|
app_name = File.basename(app_dir)
Dir.chdir(app_dir) do
puts "Building client app '#{app_name}'"
if File.exists?('./package.json')
output = `npm install` rescue `npm cache clean && npm install`
unless $?.exitstatus == 0
puts "INSTALL FAILURE:\n#{output}"
raise "Package installation failure for client app #{app_name}"
end
end
puts "\tRunning 'npm run build'..."
output = `./script/build`
unless $?.exitstatus == 0
puts "BUILD FAILURE:\n#{output}"
raise "Build script failed for client app #{app_name}"
end
puts "Client app '#{app_name}' was built successfully."
end
end
maintain_client_app_symlinks
end
desc "Cleans build javascript files"
task :clean do
require 'config/initializers/client_app_symlinks'
require 'config/initializers/plugin_symlinks'
paths_to_remove = [
Dir.glob('public/javascripts/{compiled,jst,jsx}'),
Dir.glob('public/plugins/*/javascripts/{compiled,jst,jsx}'),
'spec/javascripts/compiled',
Dir.glob('spec/plugins/*/javascripts/compiled')
]
FileUtils.rm_rf(paths_to_remove)
end
desc "Compile Coffeescript to JS"
task :coffee do
require 'coffee-script'
require 'parallel'
require 'canvas/coffee_script'
if Canvas::CoffeeScript.coffee_script_binary_is_available?
puts "--> Compiling CoffeeScript with 'coffee' binary"
dirs = Dir[Rails.root+'{app,spec}/coffeescripts/{,plugins/*/}**/*.coffee'].
map { |f| File.dirname(f) }.uniq
Parallel.each(dirs, :in_threads => Parallel.processor_count) do |dir|
destination = coffee_destination(dir)
FileUtils.mkdir_p(destination)
system("coffee -c -o #{destination} #{dir}/*.coffee")
raise "Unable to compile coffeescripts in #{dir}" if $?.exitstatus != 0
end
else
puts "--> Compiling CoffeeScript with coffee-script gem"
files = Dir[Rails.root+'{app,spec}/coffeescripts/{,plugins/*/}**/*.coffee']
Parallel.each(files, :in_threads => Parallel.processor_count) do |file|
destination = coffee_destination(file).sub(%r{\.coffee$}, '.js')
FileUtils.mkdir_p(File.dirname(destination))
File.open(destination, 'wb') do |out|
File.open(file) do |cfile|
out.write CoffeeScript.compile(cfile)
end
end
end
end
end
def coffee_destination(dir_or_file)
dir_or_file.sub('app/coffeescripts', 'public/javascripts/compiled').
sub('spec/coffeescripts', 'spec/javascripts/compiled').
sub(%r{/javascripts/compiled/plugins/([^/]+)(/|$)}, '/plugins/\\1/javascripts/compiled\\2')
end
desc "Build webpack js"
task :webpack do
if CANVAS_WEBPACK
if ENV['RAILS_ENV'] == 'production' || ENV['USE_OPTIMIZED_JS'] == 'true' || ENV['USE_OPTIMIZED_JS'] == 'True'
puts "--> Building PRODUCTION webpack bundles"
`npm run webpack-production`
else
puts "--> Building DEVELOPMENT webpack bundles"
`npm run webpack-development`
end
raise "Error running js:webpack: \nABORTING" if $?.exitstatus != 0
end
end
desc "Concatenate js bundles with r.js"
task :rjs_concat do
output = `node #{Rails.root}/node_modules/requirejs/bin/r.js -o #{Rails.root}/config/build.js 2>&1`
raise "Error running js:rjs_concat: \n#{output}\nABORTING" if $?.exitstatus != 0
end
desc "Compress js with uglify"
task :compress do
output = `npm run compress 2>&1`
raise "Error running js:compress: \n#{output}\nABORTING" if $?.exitstatus != 0
end
desc "Write config/build.js for r.js"
task :rjs_config do
require 'config/initializers/plugin_symlinks'
require 'canvas/require_js'
require 'erubis'
output = Erubis::Eruby.new(File.read("#{Rails.root}/config/build.js.erb")).
result(Canvas::RequireJs.get_binding)
File.open("#{Rails.root}/config/build.js", 'w') { |f| f.write(output) }
end
desc "Compile React JSX to JS"
task :jsx do
# Get the canvas-lms jsx and specs to compile
dirs = [["#{Rails.root}/app/jsx", "#{Rails.root}/public/javascripts/jsx"],
["#{Rails.root}/spec/javascripts/jsx", "#{Rails.root}/spec/javascripts/compiled"]]
# Get files that need compilation in plugins
plugin_jsx_dirs = Dir.glob("#{Rails.root}/gems/plugins/*/**/jsx")
plugin_jsx_dirs.each do |directory|
plugin_name = directory.match(/gems\/plugins\/([^\/]+)\//)[1]
destination = "#{Rails.root}/public/javascripts/plugins/#{plugin_name}/compiled/jsx"
FileUtils.mkdir_p(destination)
dirs << [directory, destination]
end
dirs.each do |source,dest|
opts = Rails.env.development? ? "--source-maps inline" : ""
msg = `node_modules/.bin/babel #{source} --out-dir #{dest} #{opts} 2>&1 >/dev/null`
raise msg unless $?.success?
end
end
desc "Creates ember app bundles"
task :bundle_ember_apps do
require 'lib/ember_bundle'
Dir.entries('app/coffeescripts/ember').reject { |d| d.match(/^\./) || d == 'shared' }.each do |app|
EmberBundle.new(app).build
end
end
desc "Ensure up-to-date node environment"
task :npm_install do
puts "node is: #{`node -v`.strip} (#{`which node`.strip})"
raise 'error running npm install' unless `npm install`
end
desc "Run Gulp Rev, for fingerprinting assets"
task :gulp_rev do
raise "Error reving files" unless system('node_modules/.bin/gulp rev')
end
end