lib/volt/cli/asset_compile.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module Volt
  class CLI
    desc 'precompile', 'precompile all application assets'

    def precompile
      move_to_root
      compile
    end

    private

    def compile
      say "Starting Precompile...", :red
      require 'fileutils'
      ENV['SERVER'] = 'true'
      ENV['MAPS'] = 'false'
      ENV['NO_FORKING'] = 'true'

      if !ENV['VOLT_ENV'] && !ENV['RACK_ENV']
        # Set the default env for compile
        ENV['VOLT_ENV'] = 'production'
      end

      require 'opal'
      require 'rack'
      require 'volt'
      require 'volt/volt/core'
      require 'volt/boot'
      require 'volt/server'
      require 'volt/server/rack/component_paths'
      require 'volt/server/rack/component_code'

      @root_path ||= Dir.pwd
      Volt.root  = @root_path

      @volt_app = Volt.boot(@root_path)

      @app_path = File.expand_path(File.join(@root_path, 'app'))

      say 'Compiling RB, JS, CSS, and Images...', :red
      write_files_and_manifest
      compile_manifests
      say 'Write index files...', :red
      write_index
      say "Done", :green
    end

    def write_files_and_manifest
      asset_files = AssetFiles.from_cache(@volt_app.app_url, 'main', @volt_app.component_paths)
      # Write a temp css file
      js = asset_files.javascript(@volt_app)
      css = asset_files.css
      @tmp_files = []

      File.open(Volt.root + '/app/main/app.js', 'wb') do |file|
        js.each do |type, src_or_body|
          if type == :src
            src = src_or_body
            url = src.gsub(/^#{@volt_app.app_url}\//, '')
            file.write("//= require '#{url}'\n")
          else
            body = src_or_body

            # Write to a tempfile, since sprockets can't mix requires and
            # code.

            require 'securerandom'
            hex = SecureRandom.hex
            tmp_path = Volt.root + "/app/main/__#{hex}.js"
            url = "main/__#{hex}"
            file.write("//= require '#{url}'\n")

            @tmp_files << tmp_path
            File.open(tmp_path, 'wb') {|f| f.write("#{body}\n") }
          end
        end
      end

      File.open(Volt.root + '/app/main/app.scss', 'wb') do |file|
        css.each do |link|
          url = link.gsub(/^#{@volt_app.app_url}\//, '')
          file.write("//= require '#{url}'\n")
        end
      end
    end

    def compile_manifests
      manifest = Sprockets::Manifest.new(@volt_app.sprockets, "./public#{@volt_app.app_url}/manifest.json")

      # Compile the files (and linked assets)
      manifest.compile('main/app.js')
      manifest.compile('main/app.css')

      # Clear temp files
      @tmp_files.each {|path| FileUtils.rm(path) }

      # Remove the temp files
      FileUtils.rm(Volt.root + "#{@volt_app.app_url}/main/app.js")
      FileUtils.rm(Volt.root + "#{@volt_app.app_url}/main/app.scss")
    end

    def write_index
      require 'volt/cli/base_index_renderer'

      output_path = "#{@root_path}/public/index.html"
      require 'json'

      @manifest = JSON.parse(File.read(@root_path + "/public#{@volt_app.app_url}/manifest.json"))
      output_html = BaseIndexRenderer.new(@volt_app, @manifest).html

      write_file(output_path, output_html)
    end

    def write_file(path, data)
      FileUtils.mkdir_p(File.dirname(path))

      File.open(path, 'wb') do |file|
        file.write(data)
      end
    end
  end
end