UNPKG

rails-view-loader

Version:

Rails view files (`.html.slim` , `.html.erb`, `.html.haml`) `webpack` loader.

87 lines (79 loc) 2.82 kB
const path = require('path') const execFile = require('child_process').execFile const retry = require('retry') /* Create a delimeter that is unlikely to appear in parsed code. I've split this * string deliberately in case this file accidentally ends up being transpiled */ const delimiter = `${'_'}_RAILS_VIEW_LOADER_DELIMETER__` const sourceRegex = new RegExp(`${delimiter}([\\s\\S]+)${delimiter}`) class EmptyResultError extends Error {} /* Launch Rails in a child process and run the `view_render.rb` script to * output transformed source. */ const run = (loader, config, map, callback) => { const runner = parseRunner(config.runner) const child = execFile( runner.file, runner.arguments.concat(path.join(__dirname, 'view_render.rb')), config.runnerOptions, (error, stdout) => { // Output is delimited to filter out unwanted warnings or other output // that we don't want in our files. const matches = stdout.match(sourceRegex) const transformedSource = matches && matches[1] if (transformedSource) { callback(error, transformedSource, map) } else if (error) { callback(error, stdout, map) } else { // Runner sometimes raises no error but returns empty result. // Retry 3 times to confirm. const warning = new EmptyResultError( `rails-view-loader gets an empty result from rails. resource: "${ loader.resource}".` ) callback(warning, '', map) } } ) const input = { delimiter, resource: loader.resource, layout: config.layout, variant: config.variant } child.stdin.on('error', (error) => { const message = new Error( 'rails-view-loader encountered an unexpected error while writing to stdin. Please report this to the maintainers.' ) loader.emitError(error) loader.emitError(message) }) child.stdin.write(JSON.stringify(input)) child.stdin.end() } const retryRun = (loader, config, map, callback) => { const operation = retry.operation({ retries: 3, minTimeout: 0, maxTimeout: 10 }) operation.attempt((currentAttempt) => { run(loader, config, map, (error, output, map) => { if (operation.retry(error)) { return } if (error instanceof EmptyResultError) { loader.emitWarning(error) callback(null, '', map) } else { callback(error ? operation.mainError() : null, output, map) } }) }) } /* Split the `runner` string into a `.file` and its `.arguments` */ const parseRunner = (runner) => { const runnerArguments = runner.split(' ') const runnerFile = runnerArguments.shift() return { file: runnerFile, arguments: runnerArguments } } module.exports = (loader, config, map, callback) => { retryRun(loader, config, map, callback) }