Created
          March 22, 2016 01:58 
        
      - 
      
- 
        Save rtfeldman/8885f2457fe580cc4cc2 to your computer and use it in GitHub Desktop. 
    Elm Sprockets
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | require 'open3' | |
| require 'tempfile' | |
| class ElmCompiler < Sprockets::Processor | |
| def self.default_mime_type | |
| 'text/x-elm' | |
| end | |
| def evaluate(context, _locals) | |
| pathname = context.pathname.to_s | |
| if pathname =~ /\.js.*\.elm$/ | |
| add_elm_dependencies pathname, context | |
| ElmCompiler.compile pathname | |
| else | |
| "" | |
| end | |
| end | |
| private | |
| # Add all Elm modules imported in the target file as dependencies, then | |
| # recursively do the same for each of those dependent modules. | |
| def add_elm_dependencies(filepath, context) | |
| # Turn e.g. ~/NoRedInk/app/assets/javascripts/Quiz/QuestionStoreAPI.js.elm | |
| # into just ~/NoRedInk/app/assets/javascripts/ | |
| dirname = context.pathname.to_s.gsub Regexp.new(context.logical_path + ".+$"), "" | |
| File.read(filepath).each_line do |line| | |
| # e.g. `import Quiz.QuestionStore exposing (..)` | |
| match = line.match(/^import\s+([^\s]+)/) | |
| unless match.nil? | |
| # e.g. Quiz.QuestionStore | |
| module_name = match.captures[0] | |
| # e.g. Quiz/QuestionStore | |
| dependency_logical_name = module_name.gsub(".", "/") | |
| # e.g. ~/NoRedInk/app/assets/javascripts/Quiz/QuestionStore.elm | |
| dependency_filepath = dirname + dependency_logical_name + ".elm" | |
| # If we don't find the dependency in our filesystem, assume it's because | |
| # it comes in through a third-party package rather than our sources. | |
| if File.file? dependency_filepath | |
| context.depend_on dependency_logical_name | |
| add_elm_dependencies dependency_filepath, context | |
| end | |
| end | |
| end | |
| end | |
| def self.compile(pathname) | |
| temp_file = Tempfile.new ['compiled_elm_output', '.js'] | |
| cmd = (`npm bin`).strip + "/elm-make" | |
| begin | |
| # need to specify LANG or else build will fail on jenkins | |
| # with error "elm-make: elm-stuff/build-artifacts/NoRedInk/NoRedInk/1.0.0/Quiz-QuestionStore.elmo: hGetContents: invalid argument (invalid byte sequence)" | |
| Open3.popen3({'LANG' => 'en_US.UTF-8'}, cmd, pathname.to_s, "--yes", "--output", temp_file.path, chdir: Rails.root) do |_stdin, stdout, stderr, wait_thr| | |
| compiler_output = stdout.gets(nil) | |
| stdout.close | |
| compiler_err = stderr.gets(nil) | |
| stderr.close | |
| process_status = wait_thr.value | |
| if process_status.exitstatus != 0 | |
| raise compiler_err | |
| end | |
| end | |
| temp_file.read | |
| ensure | |
| temp_file.unlink | |
| end | |
| end | |
| end | |
| Rails.application.assets.register_engine('.elm', ElmCompiler) | |
| Rails.application.assets.register_mime_type('text/x-elm', '.elm') | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment