├── .eslintrc.json
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE
├── README.md
├── compiler.js
├── erb_transformer.rb
├── index.js
├── package-lock.json
├── package.json
├── test.js
└── test
├── dependencies
├── dependency.rb
└── dependency
│ ├── hello.rb
│ └── version.rb
├── erb
├── dependencies-all.js.erb
├── dependencies.js.erb
├── engine.js.erb
├── giant.js.erb
├── runner.js.erb
├── simple.js.erb
└── sleep.js.erb
└── runner
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "standard",
3 | "plugins": ["node"],
4 | "parserOptions": {
5 | "ecmaVersion": 2017
6 | },
7 | "rules": {
8 | "node/no-unsupported-features": "error"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | Gemfile.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Send builds to container-based infrastructure
2 | # http://docs.travis-ci.com/user/workers/container-based-infrastructure/
3 | sudo: false
4 | language: node_js
5 | cache:
6 | yarn: true
7 | directories:
8 | - node_modules
9 | node_js:
10 | # LTS version(s)
11 | - "8"
12 | - "10"
13 | - "12"
14 | env:
15 | matrix:
16 | - TRAVIS_WEBPACK_VERSION="2"
17 | - TRAVIS_WEBPACK_VERSION="3"
18 | - TRAVIS_WEBPACK_VERSION="4"
19 | matrix:
20 | fast_finish: true
21 | install:
22 | - gem install erubis erubi
23 | - npm install
24 | - if [[ -v TRAVIS_WEBPACK_VERSION ]]; then npm install webpack@$TRAVIS_WEBPACK_VERSION --save-dev; fi
25 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [5.5.2] - 2019-02-05
4 | - Fix broken unicode characters in output. - #77
5 |
6 | ## [5.5.1] - 2019-01-03
7 | - Prevent webpack loader callback from being called multiple times - #76
8 |
9 | ## [5.5.0] - 2018-08-28
10 | - Allow env to be specified in options - #70
11 |
12 | ## [5.4.2] - 2018-05-08
13 | - Improve error reporting when killed by signal - #65
14 |
15 | ## [5.4.1] - 2018-03-08
16 | - Fix error clearing timeout - #61
17 |
18 | ## [5.4.0] - 2018-03-08
19 | - Remove input file limit by streaming instead of using a fixed size buffer - #56
20 |
21 | ## [5.3.0] - 2018-03-01
22 | - Replace timeout option with timeoutMs - #55
23 |
24 | ## [5.2.1] - 2017-08-25
25 | - Add timeout option - #46
26 |
27 | ## [5.2.0] - 2017-08-25
28 | **UNPUBLISHED** _Accidentally published without pulling #46_
29 |
30 | ## [5.1.0] - 2017-07-28
31 | - Support Webpack 3 - #41
32 | - Add test suite - #41
33 |
34 | ## [5.0.2] - 2017-06-13
35 | - Use `execFile` to spawn the source transformer - #37
36 |
37 | ## [5.0.1] - 2017-05-16
38 | - Support projects in paths containing spaces - #35
39 |
40 | ## [5.0.0] - 2017-04-01
41 | - **Breaking** Set default engine to `ERB` - #31
42 | - Add support for `Erubi` engine - #31
43 |
44 | ## [4.0.0] - 2017-04-01
45 | - **Breaking** Remove support for webpack 1 style configuration under `config.railsErbLoader` - #28
46 | - **Breaking** Remove support for `dependencies` in configuration (only via config comments) - #29
47 | - **Breaking** Remove `cacheable` option and comment - all files are cacheable by default - #27
48 | - **Breaking** Error when a dependency comment points to a non-existant file/directory - #29
49 | - Support adding a directory as a depedency - #29
50 | - Better error handling on invalid `runner` option - #26
51 | - Skip parsing comments in production - #29
52 |
53 | ## [3.2.0] - 2016-12-12
54 | - Add `engine` config option to specify templating engine - #21
55 | - Add `runner` config option to specify Ruby executable - #21
56 | - Deprecate `rails` config option in preference for more flexible `runner`
57 |
58 | ## [3.1.0] - 2016-12-11
59 | - Added `rails` option - #20
60 |
61 | ## [3.0.1] - 2016-11-30
62 | - Ensure support back to Node 0.10.0 - #13, #17
63 | - Remove dependency `node-uuid` - #15
64 | - Include MIT license text
65 |
66 | ## [3.0.0] - 2016-11-19
67 | - **Breaking** Use `Erubis` instead of `ERB` gem to render templates. This gem is bundled by default with Rails 3.0 and above - #7
68 |
69 | ## [2.0.0] - 2016-11-07
70 | - **Breaking** Rename project from `uh-erb-loader` to `rails-erb-loader` - #6
71 | - **Breaking** Add file caching by default - #4
72 | - Add support for query parameters
73 | - `cacheable`
74 | - `dependencies`
75 | - `dependenciesRoot`
76 | - `parseComments`
77 | - Add configuration comments
78 | - `rails-erb-loader-depedencies`
79 | - `rails-erb-loader-depedencies-root` (undocumented)
80 | - `rails-erb-loader-cacheable`
81 |
82 | ## [1.1.1] - 2016-11-07
83 | Deprecate `uh-erb-loader` in favor of `rails-erb-loader`.
84 |
85 | ## [1.1.0] - 2016-05-26
86 | - Ignore unwanted output from Rails by delimiting desired output - #1
87 |
88 | ## [1.0.0] - 2016-05-05
89 | Initial release
90 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'erubi'
4 | gem 'erubis'
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Rhys van der Waerden
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rails-erb-loader
2 |
3 | [](https://www.npmjs.com/package/rails-erb-loader)
4 | [](https://npm-stat.com/charts.html?package=rails-erb-loader&from=2016-11-07)
5 | [](http://standardjs.com/)
6 | [](https://github.com/RichardLitt/standard-readme)
7 | [](https://travis-ci.org/usabilityhub/rails-erb-loader)
8 |
9 | > Embedded Ruby (`.erb`) webpack loader for Ruby projects.
10 |
11 | Compiles Embedded Ruby template files in any Ruby project. Files are built using either the `Erubis` or `ERB` gem.
12 |
13 | ## Table of Contents
14 | - [Install](#install)
15 | - [Usage](#usage)
16 | - [Configuration](#configuration)
17 | - [Options](#options)
18 | - [Dependencies](#dependencies)
19 | - [Contribute](#contribute)
20 | - [License](#license)
21 |
22 | ## Install
23 |
24 | ### npm
25 |
26 | ```console
27 | $ npm install rails-erb-loader --save-dev
28 | ```
29 |
30 | ### yarn
31 |
32 | ```console
33 | $ yarn add -D rails-erb-loader
34 | ```
35 |
36 | ## Usage
37 |
38 | Add `rails-erb-loader` to your rules.
39 |
40 | ```js
41 | // webpack.config.js
42 |
43 | module.exports = {
44 | module: {
45 | rules: [
46 | {
47 | test: /\.erb$/,
48 | enforce: "pre",
49 | loader: "rails-erb-loader"
50 | }
51 | ]
52 | }
53 | };
54 | ```
55 |
56 | Now you can use `.erb` files in your project, for example:
57 |
58 | `app/assets/javascripts/UserFormFields.jsx.erb`
59 | ```erb
60 | /* rails-erb-loader-dependencies models/user models/image */
61 |
62 | export default function UserFormFields() {
63 | return (
64 |
65 |
68 | } />
69 |
72 | }
76 | />
77 |
80 | }
84 | max={<%= User::MAX_AGE %>}
85 | />
86 |
87 | )
88 | }
89 | ```
90 |
91 | ### Spring
92 | In case you use gem `spring`
93 | You might need customization on the loader
94 |
95 | Example from [a reply in #47](https://github.com/usabilityhub/rails-erb-loader/issues/47#issuecomment-434138107)
96 | ```js
97 | /* put this in file like /config/webpack/loaders/erb.js */
98 | /* global process:false */
99 |
100 | module.exports = {
101 | test: /\.erb$/,
102 | enforce: "pre",
103 | exclude: /node_modules/,
104 |
105 | use: [{
106 | loader: "rails-erb-loader",
107 | options: {
108 | runner: (/^win/.test(process.platform) ? "ruby " : "") + "bin/rails runner",
109 | env: {
110 | ...process.env,
111 | DISABLE_SPRING: 1,
112 | },
113 | },
114 | }],
115 | }
116 | ```
117 |
118 | ## Configuration
119 |
120 | ### Options
121 |
122 | Can be configured with [UseEntry#options](https://webpack.js.org/configuration/module/#useentry).
123 |
124 | | Option | Default | Description |
125 | | ------ | ------- | ----------- |
126 | | `dependenciesRoot` | `"app"` | The root of your Rails project, relative to webpack's working directory. |
127 | | `engine` | `"erb"` | ERB Template engine, `"erubi"`, `"erubis"` and `"erb"` are supported. |
128 | | `runner` | `"./bin/rails runner"` | Command to run Ruby scripts, relative to webpack's working directory. |
129 | | `timeoutMs` | `0` | Timeout for the runner task in milliseconds. `0` is no timeout. Set this if you want a hanging runner to error out the build. |
130 | | `env` | `process.env` | Environment variables to be passed to runner. |
131 |
132 | For example, if your webpack process is running in a subdirectory of your Rails project:
133 |
134 | ```js
135 | {
136 | loader: 'rails-erb-loader',
137 | options: {
138 | runner: '../bin/rails runner',
139 | dependenciesRoot: '../app',
140 | }
141 | }
142 | ```
143 |
144 | Also supports building without Rails:
145 |
146 | ```js
147 | {
148 | loader: 'rails-erb-loader',
149 | options: {
150 | runner: 'ruby',
151 | engine: 'erb'
152 | }
153 | }
154 | ```
155 |
156 | ### Dependencies
157 |
158 | If your `.erb` files depend on files in your Ruby project, you can list them explicitly. Inclusion of `rails-erb-loader-dependency` (or `-dependencies`) in a javascript comment block will tell webpack to watch these files - causing webpack-dev-server to rebuild when they are changed.
159 |
160 | If you don't want the directive to end up in the result, or wish to use it outside of a javascript context,
161 | include the javascript comment block inside an erb comment block.
162 |
163 | #### Watch individual files
164 |
165 | List dependencies in the comment. `.rb` extension is optional.
166 |
167 | ```js
168 | /* rails-erb-loader-dependencies models/account models/user */
169 | ```
170 |
171 | #### Watch a whole directory
172 |
173 | To watch all files in a directory, end the path in a `/`.
174 |
175 | ```js
176 | /* rails-erb-loader-dependencies ../config/locales/ */
177 | ```
178 |
179 | ## Contribute
180 |
181 | Questions, bug reports and pull requests welcome. See [GitHub issues](https://github.com/usabilityhub/rails-erb-loader/issues).
182 |
183 | ## License
184 |
185 | MIT
186 |
--------------------------------------------------------------------------------
/compiler.js:
--------------------------------------------------------------------------------
1 | var MemoryFS = require('memory-fs')
2 | var webpack = require('webpack')
3 | var defaults = require('lodash.defaults')
4 | var path = require('path')
5 |
6 | var isWebpack4 = webpack.version && webpack.version.slice(0, 1) === '4'
7 |
8 | function webpack3Compiler (config) {
9 | return webpack({
10 | entry: './test/erb/' + config.file,
11 | module: {
12 | loaders: [
13 | {
14 | test: /\.erb$/,
15 | loader: './index',
16 | options: defaults({}, config, {
17 | dependenciesRoot: './test/dependencies',
18 | timeoutMs: 2000
19 | })
20 | }
21 | ]
22 | },
23 | output: {
24 | filename: './output.js'
25 | }
26 | })
27 | }
28 |
29 | function webpack4Compiler (config) {
30 | return webpack({
31 | entry: './test/erb/' + config.file,
32 | mode: 'development',
33 | module: {
34 | rules: [
35 | {
36 | test: /\.erb$/,
37 | loader: './index',
38 | options: defaults({}, config, {
39 | dependenciesRoot: './test/dependencies',
40 | timeoutMs: 2000
41 | })
42 | }
43 | ]
44 | },
45 | output: {
46 | path: __dirname,
47 | filename: 'output.js'
48 | }
49 | })
50 | }
51 |
52 | var webpackCompiler = isWebpack4 ? webpack4Compiler : webpack3Compiler
53 |
54 | var fs = new MemoryFS()
55 |
56 | function compile (config, callback) {
57 | config.runner = config.runner || 'ruby'
58 | config.engine = config.engine || 'erb'
59 |
60 | var compiler = webpackCompiler(config)
61 | compiler.outputFileSystem = fs
62 | compiler.run(callback)
63 | }
64 |
65 | function readOutput () {
66 | var fileContent = fs.readFileSync(path.resolve(__dirname, './output.js'))
67 | return fileContent.toString()
68 | }
69 |
70 | exports.compile = compile
71 | exports.readOutput = readOutput
72 |
--------------------------------------------------------------------------------
/erb_transformer.rb:
--------------------------------------------------------------------------------
1 | delimiter = ARGV[0]
2 | engine = ARGV[1]
3 | handler = case engine
4 | when 'erubi'
5 | require 'erubi'
6 | Erubi::Engine
7 | when 'erubis'
8 | require 'erubis'
9 | Erubis::Eruby
10 | when 'erb'
11 | require 'erb'
12 | ERB
13 | else raise "Unknown templating engine `#{engine}`"
14 | end
15 |
16 | if engine == 'erubi'
17 | puts "#{delimiter}#{eval(handler.new(STDIN.read).src)}#{delimiter}"
18 | else
19 | puts "#{delimiter}#{handler.new(STDIN.read).result}#{delimiter}"
20 | end
21 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs')
2 | var spawn = require('child_process').spawn
3 | var path = require('path')
4 | var getOptions = require('loader-utils').getOptions
5 | var defaults = require('lodash.defaults')
6 | var util = require('util')
7 |
8 | function pushAll (dest, src) {
9 | Array.prototype.push.apply(dest, src)
10 | }
11 |
12 | /* Create a delimeter that is unlikely to appear in parsed code. I've split this
13 | * string deliberately in case this file accidentally ends up being transpiled
14 | */
15 | var ioDelimiter = '_' + '_RAILS_ERB_LOADER_DELIMETER__'
16 |
17 | /* Match any block comments that start with the string `rails-erb-loader-`. */
18 | var configCommentRegex = /\/\*\s*rails-erb-loader-([a-z-]*)\s*([\s\S]*?)\s*\*\//g
19 |
20 | /* Absolute path to the Ruby script that does the ERB transformation. */
21 | var runnerPath = path.join(__dirname, 'erb_transformer.rb')
22 |
23 | /* Takes a path and attaches `.rb` if it has no extension nor trailing slash. */
24 | function defaultFileExtension (dependency) {
25 | return /((\.\w*)|\/)$/.test(dependency) ? dependency : dependency + '.rb'
26 | }
27 |
28 | /* Split the `runner` string into a `.file` and its `.arguments` */
29 | function parseRunner (runner) {
30 | var runnerArguments = runner.split(' ')
31 | var runnerFile = runnerArguments.shift()
32 |
33 | return { file: runnerFile, arguments: runnerArguments }
34 | }
35 |
36 | /* Get each space separated path, ignoring any empty strings. */
37 | function parseDependenciesList (root, string) {
38 | return string.split(/\s+/).reduce(function (accumulator, dependency) {
39 | if (dependency.length > 0) {
40 | var absolutePath = path.resolve(root, defaultFileExtension(dependency))
41 | accumulator.push(absolutePath)
42 | }
43 | return accumulator
44 | }, [])
45 | }
46 |
47 | /* Update config object in place with comments from file */
48 | function parseDependencies (source, root) {
49 | var dependencies = []
50 | var match = null
51 | while ((match = configCommentRegex.exec(source))) {
52 | var option = match[1]
53 | var value = match[2]
54 | switch (option) {
55 | case 'dependency':
56 | case 'dependencies':
57 | pushAll(dependencies, parseDependenciesList(root, value))
58 | break
59 | default:
60 | console.warn(
61 | 'WARNING: Unrecognized configuration command ' +
62 | '"rails-erb-loader-' + option + '". Comment ignored.'
63 | )
64 | }
65 | }
66 | return dependencies
67 | }
68 |
69 | /* Launch Rails in a child process and run the `erb_transformer.rb` script to
70 | * output transformed source.
71 | */
72 | function transformSource (runner, config, source, map, callback) {
73 | var callbackCalled = false
74 | var subprocessOptions = {
75 | stdio: ['pipe', 'pipe', process.stderr],
76 | env: config.env
77 | }
78 |
79 | var child = spawn(
80 | runner.file,
81 | runner.arguments.concat(
82 | runnerPath,
83 | ioDelimiter,
84 | config.engine
85 | ),
86 | subprocessOptions
87 | )
88 | var timeoutId = config.timeoutMs
89 | ? setTimeout(function () { child.kill() }, config.timeoutMs)
90 | : -1
91 |
92 | var dataBuffers = []
93 | child.stdout.on('data', function (data) {
94 | if (config.debug) { console.log(data) }
95 | dataBuffers.push(data)
96 | })
97 |
98 | // NOTE: From 'exit' event docs (assumed to apply to 'close' event)
99 | //
100 | // "If the process exited, code is the final exit code of the process,
101 | // otherwise null. If the process terminated due to receipt of a signal,
102 | // signal is the string name of the signal, otherwise null. One of the two
103 | // will always be non-null."
104 | //
105 | // see: https://nodejs.org/api/child_process.html#child_process_event_exit
106 | child.on('close', function (code, signal) {
107 | if (callbackCalled) return
108 |
109 | if (code === 0) {
110 | // Output is delimited to filter out unwanted warnings or other output
111 | // that we don't want in our files.
112 | var sourceRegex = new RegExp(ioDelimiter + '([\\s\\S]+)' + ioDelimiter)
113 | var matches = Buffer.concat(dataBuffers).toString().match(sourceRegex)
114 | var transformedSource = matches && matches[1]
115 | if (timeoutId !== -1) {
116 | clearTimeout(timeoutId)
117 | }
118 | callback(null, transformedSource, map)
119 | } else if (child.killed) {
120 | // `child.killed` is true only if the process was killed by `ChildProcess#kill`,
121 | // ie. after a timeout.
122 | callback(new Error(
123 | 'rails-erb-loader took longer than the specified ' + config.timeoutMs +
124 | 'ms timeout'
125 | ))
126 | } else if (signal !== null) {
127 | callback(new Error('rails-erb-loader was terminated with signal: ' + signal))
128 | } else {
129 | callback(new Error('rails-erb-loader failed with code: ' + code))
130 | }
131 |
132 | callbackCalled = true
133 | })
134 |
135 | child.on('error', function (error) {
136 | if (callbackCalled) return
137 |
138 | callback(error)
139 | callbackCalled = true
140 | })
141 |
142 | child.stdin.on('error', function (error) {
143 | console.error(
144 | 'rails-erb-loader encountered an unexpected error while writing to stdin: "' +
145 | error.message + '". Please report this to the maintainers.'
146 | )
147 | })
148 | child.stdin.write(source)
149 | child.stdin.end()
150 | }
151 |
152 | function addDependencies (loader, paths, callback) {
153 | var remaining = paths.length
154 |
155 | if (remaining === 0) callback(null)
156 |
157 | paths.forEach(function (path) {
158 | fs.stat(path, function (error, stats) {
159 | if (error) {
160 | if (error.code === 'ENOENT') {
161 | callback(new Error('Could not find dependency "' + path + '"'))
162 | } else {
163 | callback(error)
164 | }
165 | } else {
166 | if (stats.isFile()) {
167 | loader.addDependency(path)
168 | } else if (stats.isDirectory()) {
169 | loader.addContextDependency(path)
170 | } else {
171 | console.warning(
172 | 'rails-erb-loader ignored dependency that was neither a file nor a directory'
173 | )
174 | }
175 | remaining--
176 | if (remaining === 0) callback(null)
177 | }
178 | })
179 | })
180 | }
181 |
182 | var setTimeoutMsFromTimeoutInPlace = util.deprecate(function (config) {
183 | if (config.timeoutMs != null) {
184 | throw new TypeError(
185 | 'Both options `timeout` and `timeoutMs` were set -- please just use ' +
186 | '`timeoutMs`'
187 | )
188 | }
189 | config.timeoutMs = config.timeout * 1000
190 | delete config.timeout
191 | }, 'rails-erb-loader `timeout` option is deprecated in favor of `timeoutMs`')
192 |
193 | module.exports = function railsErbLoader (source, map) {
194 | var loader = this
195 |
196 | // Mark loader cacheable. Must be called explicitly in webpack 1.
197 | // see: https://webpack.js.org/guides/migrating/#cacheable
198 | loader.cacheable()
199 |
200 | // Get options passed in the loader query, or use defaults.
201 | // Modifying the return value of `getOptions` is not permitted.
202 | var config = defaults({}, getOptions(loader), {
203 | dependenciesRoot: 'app',
204 | runner: './bin/rails runner',
205 | engine: 'erb',
206 | env: process.env,
207 | debug: false
208 | })
209 |
210 | if (config.timeout !== undefined) {
211 | setTimeoutMsFromTimeoutInPlace(config)
212 | }
213 |
214 | // Dependencies are only useful in development, so don't bother searching the
215 | // file for them otherwise.
216 | var dependencies = process.env.NODE_ENV === 'development'
217 | ? parseDependencies(source, config.dependenciesRoot)
218 | : []
219 |
220 | // Parse the runner string before passing it down to `transfromSource`
221 | var runner = parseRunner(config.runner)
222 |
223 | var callback = loader.async()
224 |
225 | // Register watchers for any dependencies.
226 | addDependencies(loader, dependencies, function (error) {
227 | if (error) {
228 | callback(error)
229 | } else {
230 | transformSource(runner, config, source, map, callback)
231 | }
232 | })
233 | }
234 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rails-erb-loader",
3 | "version": "5.5.2",
4 | "description": "Embedded Ruby (`.erb`) `webpack` loader for Ruby projects.",
5 | "main": "index.js",
6 | "engines": {
7 | "node": ">=0.10.0"
8 | },
9 | "jest": {
10 | "testEnvironment": "node"
11 | },
12 | "scripts": {
13 | "lint": "eslint index.js",
14 | "test": "jest",
15 | "test-webpack-2": "npm install webpack@2 --no-save && jest",
16 | "test-webpack-3": "npm install webpack@3 --no-save && jest",
17 | "test-webpack-4": "npm install webpack@4 --no-save && jest"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/usabilityhub/rails-erb-loader.git"
22 | },
23 | "keywords": [
24 | "erb",
25 | "loader",
26 | "webpack",
27 | "ruby",
28 | "rails"
29 | ],
30 | "author": "Rhys van der Waerden (https://github.com/rhys-vdw)",
31 | "contributors": [
32 | "Ammar Alammar (https://github.com/a3ammar)",
33 | "Guillermo Iguaran (https://github.com/guilleiguaran)",
34 | "Jeremiah Atwood (https://github.com/atwoodjw)",
35 | "Jonathan Lehman (https://github.com/jdlehman)",
36 | "Maria Kousta (https://github.com/mkousta)",
37 | "Stanislav E. Govorov (https://github.com/govorov)",
38 | "Faraz Yashar (https://github.com/fny)",
39 | "Evan Pavlica (https://github.com/xicreative)",
40 | "PikachuEXE (https://github.com/PikachuEXE)",
41 | "Joseph Farina (https://github.com/josephfarina)",
42 | "Andy Braga (https://github.com/bragovo)"
43 | ],
44 | "license": "MIT",
45 | "bugs": {
46 | "url": "https://github.com/usabilityhub/rails-erb-loader/issues"
47 | },
48 | "homepage": "https://github.com/usabilityhub/rails-erb-loader#readme",
49 | "dependencies": {
50 | "loader-utils": "^2.0.0",
51 | "lodash.defaults": "^4.2.0"
52 | },
53 | "peerDependencies": {
54 | "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0"
55 | },
56 | "devDependencies": {
57 | "eslint": "^5.15.3",
58 | "eslint-config-standard": "^12.0.0",
59 | "eslint-plugin-import": "^2.16.0",
60 | "eslint-plugin-node": "^8.0.1",
61 | "eslint-plugin-promise": "^4.0.1",
62 | "eslint-plugin-standard": "^4.0.0",
63 | "jest": "^29.3.1",
64 | "memory-fs": "^0.4.1",
65 | "webpack": "^5.75.0"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | var compiler = require('./compiler')
2 |
3 | function compile2 (config, done, successCallback) {
4 | compiler.compile(config, function (error, stats) {
5 | if (error) {
6 | fail(error)
7 | done()
8 | } else {
9 | successCallback(stats)
10 | }
11 | })
12 | }
13 |
14 | function expectInOutput (str) {
15 | expect(compiler.readOutput()).toEqual(expect.stringContaining(str))
16 | }
17 |
18 | test('loads a simple file', function (done) {
19 | compile2({ file: 'simple.js.erb' }, done, function (stats) {
20 | expect(stats.compilation.errors).toEqual([])
21 | expectInOutput("var helloWorld = 'Hello World'")
22 | done()
23 | })
24 | })
25 |
26 | test('loads with erb', function (done) {
27 | compile2({ file: 'engine.js.erb', engine: 'erb' }, done, function (stats) {
28 | expect(stats.compilation.errors).toEqual([])
29 | expectInOutput("var engine = 'erb'")
30 | done()
31 | })
32 | })
33 |
34 | test('loads with erubis', function (done) {
35 | compile2({ file: 'engine.js.erb', engine: 'erubis' }, done, function (stats) {
36 | expect(stats.compilation.errors).toEqual([])
37 | expectInOutput("var engine = 'erubis'")
38 | done()
39 | })
40 | })
41 |
42 | test('loads with erubi', function (done) {
43 | compile2({ file: 'engine.js.erb', engine: 'erubi' }, done, function (stats) {
44 | expect(stats.compilation.errors).toEqual([])
45 | expectInOutput("var engine = 'erubi'")
46 | done()
47 | })
48 | })
49 |
50 | test('loads through a Rails-like runner', function (done) {
51 | compile2({ file: 'runner.js.erb', runner: './test/runner' }, done, function (stats) {
52 | expect(stats.compilation.errors).toEqual([])
53 | expectInOutput("var env = 'test'")
54 | done()
55 | })
56 | })
57 |
58 | test('loads with env specified in option', function (done) {
59 | compile2({ file: 'runner.js.erb', runner: './test/runner', env: { ENV: 'custom' } }, done, function (stats) {
60 | expect(stats.compilation.errors).toEqual([])
61 | expectInOutput("var env = 'custom'")
62 | done()
63 | })
64 | })
65 |
66 | test('does not error with large files', function (done) {
67 | compile2({ file: 'giant.js.erb' }, done, function (stats) {
68 | expect(stats.compilation.errors).toEqual([])
69 | expect(compiler.readOutput()).toMatch(/var bigData = 'a{204740}'/)
70 | done()
71 | })
72 | })
73 |
74 | test('times out with error (timeoutMs: 1000)', function (done) {
75 | compile2({ file: 'sleep.js.erb', timeoutMs: 1000 }, done, function (stats) {
76 | expect(stats.compilation.errors.length).toEqual(1)
77 | expect(stats.compilation.errors[0].message).toMatch(
78 | 'rails-erb-loader took longer than the specified 1000ms timeout'
79 | )
80 | done()
81 | })
82 | })
83 |
84 | test('times out with error (DEPRECATED timeout: 1)', function (done) {
85 | compile2({ file: 'sleep.js.erb', timeout: 1, timeoutMs: null }, done, function (stats) {
86 | expect(stats.compilation.errors[0].message).toMatch(
87 | 'rails-erb-loader took longer than the specified 1000ms timeout'
88 | )
89 | done()
90 | })
91 | })
92 |
93 | test('fails when both timeout and timeoutMs are set', function (done) {
94 | // TODO this spec is causing jest not to clean up properly, we get a console warning
95 | // 'Jest did not exit one second after the test run has completed.'
96 | compile2({ file: 'sleep.js.erb', timeout: 1, timeoutMs: 1000 }, done, function (stats) {
97 | expect(stats.compilation.errors[0].message).toMatch(
98 | 'TypeError: Both options `timeout` and `timeoutMs` were set'
99 | )
100 | done()
101 | })
102 | })
103 |
104 | test.skip('loads single file dependencies in dev', function (done) {
105 | var prevEnv = process.env.NODE_ENV
106 | compile2({ file: 'dependencies.js.erb' }, done, function (stats) {
107 | process.env.NODE_ENV = 'development'
108 | expect(stats.compilation.errors).toEqual([])
109 |
110 | // TODO: Check that dependencies/dependency.rb and dependencies/dependency/version.rb
111 | // are being watched
112 |
113 | done()
114 | })
115 | process.env.NODE_ENV = prevEnv
116 | })
117 |
118 | test.skip('loads directory dependencies in dev', function (done) {
119 | var prevEnv = process.env.NODE_ENV
120 | compile2({ file: 'dependencies-all.js.erb' }, done, function (stats) {
121 | process.env.NODE_ENV = 'development'
122 | expect(stats.compilation.errors).toEqual([])
123 |
124 | // TODO: Check that the whole dependencies tree is being watched
125 |
126 | done()
127 | })
128 | process.env.NODE_ENV = prevEnv
129 | })
130 |
--------------------------------------------------------------------------------
/test/dependencies/dependency.rb:
--------------------------------------------------------------------------------
1 | module Dependency
2 | end
3 |
--------------------------------------------------------------------------------
/test/dependencies/dependency/hello.rb:
--------------------------------------------------------------------------------
1 | module Dependency
2 | class Hello
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/dependencies/dependency/version.rb:
--------------------------------------------------------------------------------
1 | module Dependency
2 | VERSION = '1.0.0'.freeze
3 | end
4 |
--------------------------------------------------------------------------------
/test/erb/dependencies-all.js.erb:
--------------------------------------------------------------------------------
1 | /* rails-erb-loader-dependencies dependency dependency/ */
2 |
--------------------------------------------------------------------------------
/test/erb/dependencies.js.erb:
--------------------------------------------------------------------------------
1 | /* rails-erb-loader-dependencies dependency dependency/version */
2 |
--------------------------------------------------------------------------------
/test/erb/engine.js.erb:
--------------------------------------------------------------------------------
1 | <%
2 | def erb_engine
3 | return 'erb' if defined?(ERB)
4 | return 'erubis' if defined?(Erubis)
5 | return 'erubi' if defined?(Erubi)
6 | end
7 | %>
8 | var engine = '<%= erb_engine %>'
9 |
--------------------------------------------------------------------------------
/test/erb/giant.js.erb:
--------------------------------------------------------------------------------
1 | var bigData = '<%= 'a'*204_740 %>';
2 |
--------------------------------------------------------------------------------
/test/erb/runner.js.erb:
--------------------------------------------------------------------------------
1 | var env = '<%= Runner.env %>'
2 |
--------------------------------------------------------------------------------
/test/erb/simple.js.erb:
--------------------------------------------------------------------------------
1 | var helloWorld = '<%= "Hello World" %>'
2 |
--------------------------------------------------------------------------------
/test/erb/sleep.js.erb:
--------------------------------------------------------------------------------
1 | <% sleep(10) %>
2 |
--------------------------------------------------------------------------------
/test/runner:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env ruby
2 |
3 | require 'ostruct'
4 | Runner = OpenStruct.new(env: ENV["ENV"] || 'test')
5 |
6 | def perform(file, *command_argv)
7 | ARGV.replace(command_argv)
8 | $0 = file
9 | Kernel.load(file)
10 | end
11 |
12 | perform(*ARGV)
13 |
--------------------------------------------------------------------------------