opal-webpack-loader 0.9.11 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df7daa4166a459e2bbd8942eb051e176718b2f0f2b3e0a8eec03d4c3c7232607
4
- data.tar.gz: e4ca6d4e0a2f3ccb8696d1d6d4cfa6f0812e9342511ca888d26a725a98370701
3
+ metadata.gz: 75cfc2e9527b252335ad359e1eb5c7aa476cec879ed76c4501b686a50f39b1f2
4
+ data.tar.gz: b6d13eac5c5eaa0e3c46dfd15b8f59d01d59124f92608c741e93952c87bb04f6
5
5
  SHA512:
6
- metadata.gz: df26e49ff98da208b57f55e253b6c4c9f5a25ac3dba28b7d9485882f8e207069e24acbaf730368a2da543e2d57030e4c36c230350bfb025aed6c3b50f0ebfcc9
7
- data.tar.gz: 2367ec570bc9ca4fcb28b1829c992ab3ee2365e3119b90040696b0bf2da55427ddafb0ff0ec128c645b4c1a7d701a5cc3bb87be03d841006f236a532dd91e1df
6
+ metadata.gz: c9edddd5f0a21625c5376dbf609e594a35bfe36ab84ca2fb804fa7f011093e8a45aa516530bb0dceceec4dcc069619dc0e7c31ceecfd3f68a5ad0c6caf39699f
7
+ data.tar.gz: f21627293c524a6db7f7c53f89e83f13f77519597133c05dd992173b7d2cff05f0ab915cfe7eb8e52f036ce448f3905e572d75a2d345cefe93990ece36ad342b
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ <h1 align="center">
2
+ <img src="https://raw.githubusercontent.com/isomorfeus/opal-webpack-loader/master/docs/owl.png"
3
+ align="center" title="Opal logo by Elia Schito combined with Webpack Logo" width="111" height="125" />
4
+ <br/>
5
+ opal-webpack-loader<br/>
6
+ <img src="https://img.shields.io/badge/Opal-Ruby%20💛%20JavaScript%20💛%20Webpack-yellow.svg?logo=ruby&style=social&logoColor=777"/>
7
+ </h1>
8
+
9
+ Bundle assets with webpack, resolve and compile opal ruby files and import them in the bundle, without sprockets or the webpacker gem
10
+ (but can be used with both of them too).
11
+ Includes a loader and resolver plugin for webpack.
12
+
13
+ ### Community and Support
14
+ At the [Isomorfeus Framework Project](http://isomorfeus.com)
15
+
16
+ ### Tested
17
+ [TravisCI](https://travis-ci.org): [![Build Status](https://travis-ci.org/isomorfeus/opal-webpack-loader.svg?branch=master)](https://travis-ci.org/isomorfeus/opal-webpack-loader)
18
+
19
+ ### Features
20
+ - comes with a installer for rails and other frameworks
21
+ - webpack based build process
22
+ - very fast, asynchronous and parallel builds of opal code:
23
+ opal-webpack-loader-0.7.1 compiles all of opal, a bunch of gems and over 19000SLC on a
24
+ Intel® Core™ i7-7700HQ CPU @ 2.80GHz × 8, with 8 workers in around 1850ms
25
+ - support for memcached or redis as compiler cache
26
+ - fast builds on windows too, parallel when building multiple assets with parallel webpack
27
+ - opal modules are packaged as es6 modules
28
+ - support for rails with webpacker
29
+ - other webpack features become available, like:
30
+ - source maps
31
+ - multiple targets: web (for browsers), node (for server side rendering) and webworker (for Web Workers)
32
+ - hot module reloading for opal ruby code and stylesheets and html views
33
+ - tree shaking
34
+ - code splitting
35
+ - lazy loading
36
+ - everything else webpack can do, like loading stylesheets, etc.
37
+
38
+ ### Requirements
39
+ - opal-webpack-loader consists of 2 parts, the npm package and the gem, both are required and must be the same version.
40
+ - webpack ^4.46
41
+ - webpack-dev-server ^3.11.0
42
+ - one of the ES6 modules branches of opal
43
+ - [PR#1973](https://github.com/opal/opal/pull/1973), (experimental) implementing ES6 modules and changes for 'strict' mode,
44
+ based on Opal master 1.0.0 using javascript string objects "mutable strings" by default for all strings
45
+
46
+ `gem 'opal', github: 'janbiedermann/opal', branch: 'es6_modules_string'`
47
+
48
+ - [PR#1976](https://github.com/opal/opal/pull/1976), (recommended) implementing ES6 modules and changes for 'strict' mode,
49
+ based on Opal master 1.1.0 using javascript string primitives and providing nice features like `require_lazy 'my_module'`
50
+
51
+ `gem 'opal', github: 'janbiedermann/opal', branch: 'es6_modules_1_1'`
52
+
53
+ - if you have the webpacker gem installed somewhere, it should be a version supporting webpack 4
54
+ - ruby, version 2.5 or higher recommended
55
+ - bundler, latest version recommended
56
+
57
+ ### Installation
58
+
59
+ #### Using the installer
60
+ First install the gem:
61
+ ```
62
+ gem install 'opal-webpack-loader'
63
+ ```
64
+
65
+ Continue here:
66
+ - [Install for Rails like projects](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/installation_rails.md)
67
+ - [Install for Cuba, Roda, Sinatra and other projects with a flat structure](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/installation_flat.md)
68
+ - [Manual Installation](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/installation_manual.md)
69
+
70
+ ### Example applications
71
+ - [Are here](https://github.com/isomorfeus/opal-webpack-loader/tree/master/example_apps/)
72
+ - A minimal webpack only example from @sunrick is [here](https://github.com/sunrick/opal-hello-world-webpack).
73
+
74
+ ### General Usage without Webpacker
75
+
76
+ After installing owl with the installer, three scripts are provided in package.json:
77
+ - `development` - runs the webpack-dev-server, use for general development, provides fast reloads, entry is application.js
78
+ - `debug` - runs the webpack-dev-server, use for debugging, provides source maps, entry is application_debug.js. Additional debugging tools may be added there.
79
+ - `production_build` - runs webpack to build assets for production, entry is application.js
80
+
81
+ These scripts can for example be run with:
82
+ `yarn run debug` or `npm run debug`
83
+
84
+ The default config provides several targets and entries:
85
+
86
+ - **Browser**: the webpack target is 'web' and the javascript entry file for imports is `application.js` - general use for the application with all
87
+ browser features, the opal ruby entry file is `opal_loader.rb` in the opal or app/opal directory of the app.
88
+ - **Server Side Rendering**: the webpack target is `node` and the javascript entry file for imports is `application_ssr.js` - general use for the
89
+ application server side rendering, several Browser features are unavailable, no `window`, no `document`, some node features are available,
90
+ like `Buffer`, the opal ruby entry file is `opal_loader.rb` in the opal or app/opal directory of the app.
91
+ (meant to be used with isomorfeus-speednode, standard ExecJS limitations prevent certain webpack features)
92
+ - **Web Worker**: the webpack target is 'webworker' and the javascript entry file for imports is `application_webworker.js` - used to initialize Web
93
+ Workers in the browser, the opal ruby entry file is `opal_webworker_loader.rb` in the opal or app/opal directory of the app.
94
+
95
+ Only the browser target is build by default. To builds the other target, just add the needed targets to the last line of the webpack config,
96
+ for example to `development.js`:
97
+ default config:
98
+ ```javascript
99
+ module.exports = [ browser ];
100
+ ```
101
+ modified config with ssr and web_worker targets enabled:
102
+ ```javascript
103
+ module.exports = [ browser, ssr, web_worker ];
104
+ ```
105
+ Same works for the `debug.js` and `production.js` webpack config files.
106
+
107
+ Also a Procfile has been installed, for rails its easy to startup rails and webpack with foreman:
108
+ `foreman start` (`gem install foreman` if you dont have it already). It will start rails and webpack-dev-server with the development script.
109
+
110
+ For non rails installation check the Procfile and add a starter for your app.
111
+
112
+ #### Opal Ruby Application Files
113
+ For rails installations with the installer they all go into: `app/opal`, for flat installations in the `opal` directory.
114
+ In this directory there already is a `opal_loader.rb` which is the entry point for your app.
115
+
116
+ #### Stylesheets
117
+ Stylesheets are hot reloaded too with the default config installed by the installer. Also they are imported into application.js by default.
118
+ For rails like applications stylesheets are in `app/assets/stylesheets/application.css`, for flat applications they are in `styles/application.css`.
119
+ SCSS is supported too by the default config.
120
+
121
+ #### Views
122
+ For rails like applications a watcher for `app/views` is installed by default. The watcher will trigger a page reload when views are changed.
123
+ For flat applications nothing is configured by default, as there are to many ways to generate views, they are not even needed with
124
+ frameworks like isomorfeus. Instead the section for configuring a view watcher is included in the development.js and debug.js webpack
125
+ config, but it is commented out. Please see those files and adjust to your liking.
126
+
127
+ #### Parallel compilation for speed
128
+
129
+ Since version 0.8.0 the number of CPUs is automatically determined and a appropriate number of of compile server workers is started automatically.
130
+
131
+ ### Source Maps
132
+
133
+ [Source Maps](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/source_maps.md)
134
+
135
+ ### Hot Module Reloading
136
+ [Hot Module Reloading](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/hot_module_reloading.md)
137
+
138
+ ### Opal Load Path
139
+ The projects directory for opal ruby files must be in the opal load path. This is done in the initializer for rails apps in
140
+ config/initializers/opal_webpack_loader.rb or in 'owl_init.rb' for non rails apps, for example:
141
+ ```ruby
142
+ Opal.append_path(File.realdirpath('app/opal'))
143
+ ```
144
+
145
+ ### View Helper
146
+ In Rails or frameworks that support `javscript_include_tag`, add to the app/helpers/application_helper.rb
147
+ ```ruby
148
+ module ApplicationHelper
149
+ include OpalWebpackLoader::RailsViewHelper
150
+ ```
151
+ in other frameworks that dont have a `javascript_include_tag`:
152
+ ```ruby
153
+ module MyProjectsViewThings
154
+ include OpalWebpackLoader::ViewHelper
155
+ ```
156
+
157
+ Then you can use in your views:
158
+ ```ruby
159
+ owl_script_tag('application.js')
160
+ ```
161
+ #### Compile Server and app_loader.rb
162
+ For non rails projects, determining Opal load paths, for the resolver and compile server to work properly, may not be obvious. For these cases
163
+ a file `app_loader.rb` in the projects root can be created which just loads all requirements without starting anything.
164
+ Usually it would just setup bundler with the appropriate options, for example:
165
+ ```ruby
166
+ require 'bundler/setup'
167
+ if ENV['RACK_ENV'] && ENV['RACK_ENV'] == 'test'
168
+ Bundler.require(:default, :test)
169
+ elsif ENV['RACK_ENV'] && ENV['RACK_ENV'] == 'production'
170
+ Bundler.require(:default, :production)
171
+ else
172
+ Bundler.require(:default, :development)
173
+ end
174
+ Opal.append_path(File.realdirpath('opal')) # this is a good place to add the directory with opal files to the opal load path
175
+ ```
176
+ When this file exists, the compile server will load it and generate Opal load paths accordingly for the resolver.
177
+
178
+ #### Project configuration options for the view helper
179
+ These setting are in the initializer in config/initializers/opal_webpack_loader.rb for rails like apps, or owl_init.rb for others.
180
+ ```ruby
181
+ OpalWebpackLoader.use_manifest = false
182
+ ```
183
+ If the manifest file should be used, use_manifest should be true.
184
+ ```ruby
185
+ OpalWebpackLoader.manifest_path = File.join(Dir.getwd, 'public', 'assets', 'manifest.json')
186
+ ```
187
+ Sets the path to the webpack (with the [webpack-manifest-plugin](https://www.npmjs.com/package/webpack-manifest-plugin)) generated manifest.json to look up assets.
188
+ ```ruby
189
+ OpalWebpackLoader.client_asset_path = 'http://localhost:3035/assets/'
190
+ ```
191
+ The path to prepend to the assets as configured in the webpack config 'publicPath'.
192
+ In the config example below its `publicPath: 'http://localhost:3025/assets'` so
193
+ client_asset_path should be set to the same.
194
+
195
+ For **production** use with readily precompiled and compressed assets which contain a fingerprint in the name (webpacks [chunkhash]),
196
+ and if the path in the manifest is the full path to the asset as configured in webpack,
197
+ these settings would work:
198
+ ```ruby
199
+ OpalWebpackLoader.use_manifest = true
200
+ OpalWebpackLoader.manifest_path = File.join(Dir.getwd, 'public', 'assets', 'manifest.json')
201
+ OpalWebpackLoader.client_asset_path = ''
202
+ ```
203
+
204
+ For **development** use with webpack-dev-server, with no manifest, these settings would work:
205
+ ```ruby
206
+ OpalWebpackLoader.use_manifest = false
207
+ OpalWebpackLoader.manifest_path = File.join(Dir.getwd, 'public', 'assets', 'manifest.json') # doesn't matter, not used
208
+ OpalWebpackLoader.client_asset_path = 'http://localhost:3035/assets/'
209
+ ```
210
+ ### Advanced Options
211
+ [Advanced Options](https://github.com/isomorfeus/opal-webpack-loader/blob/master/docs/advanced_options.md)
212
+ ### Tests
213
+ - clone the repo
214
+ - `bundle install`
215
+ - `bundle exec rspec`
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'digest'
3
- require 'open3'
4
3
  require 'oj'
5
4
  require 'c_lexer'
6
5
  require 'optparse'
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+ require 'digest'
3
+ require 'oj'
4
+ require 'c_lexer'
5
+ require 'optparse'
6
+ require 'opal/paths'
7
+ require 'opal/source_map'
8
+ require 'opal/compiler'
9
+ require 'opal-webpack-loader/load_path_manager'
10
+ require 'opal-webpack-loader/pipe_server'
11
+
12
+ modules_to_require = []
13
+ compiler_options = {}
14
+ compile_server_options = {}
15
+ cache = false
16
+
17
+ OptionParser.new do |opts|
18
+ opts.on('-r', '--require MODULE', 'Require the module before starting the compile server.') do |m|
19
+ modules_to_require << m
20
+ end
21
+
22
+ opts.on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i|
23
+ $:.unshift(File.expand_path(i))
24
+ end
25
+
26
+ opts.on('-d', '--dynamic-require-severity SEVERITY', 'Compiler option, one of: error, warning, ignore.') do |s|
27
+ if %w[error warning ignore].include?(s)
28
+ compiler_options[:dynamic_require_severity] = s.to_sym
29
+ end
30
+ end
31
+
32
+ opts.on('-t', '--true FLAG', 'Set compiler flag to true.' ) do |f|
33
+ compiler_options[f.to_sym] = true
34
+ end
35
+
36
+ opts.on('-f', '--false FLAG', 'Set compiler flag to false.' ) do |f|
37
+ compiler_options[f.to_sym] = false
38
+ end
39
+
40
+ opts.on('-l', '--load-paths-cache PATH', 'Path to load path cache json') do |l|
41
+ compile_server_options[:load_paths_cache] = l
42
+ end
43
+
44
+ opts.on('-p', '--pipe-name PATH', 'Name of the named pipe.') do |p|
45
+ compile_server_options[:pipe_name] = p
46
+ end
47
+
48
+ opts.on('-m', '--memcached URL', 'URL of memcached server. Will enable use of memcached for caching compiler results.') do |m|
49
+ compile_server_options[:memcached] = m
50
+ require 'dalli'
51
+ cache = Dalli::Client.new(compile_server_options[:memchached])
52
+ end
53
+
54
+ opts.on('-e', '--redis URL', 'URL of redis server. Will enable use of redis for caching compiler results.') do |e|
55
+ compile_server_options[:redis] = e
56
+ require 'redis'
57
+ cache = Redis.new(url: compile_server_options[:redis])
58
+ end
59
+ end.parse!
60
+
61
+ compiler_options.merge!(es6_modules: true)
62
+
63
+ modules_to_require.each do |mod|
64
+ require mod
65
+ end
66
+
67
+ def compile(request, cache, compiler_options)
68
+ begin
69
+ request_json = Oj.load(request.chop!, mode: :strict)
70
+
71
+ compile_source_map = request_json["source_map"]
72
+ filename = request_json["filename"]
73
+ source = File.read(filename)
74
+ if cache
75
+ source_digest = Digest::SHA1.hexdigest(source)
76
+ key = "owl_#{compiler_options_digest}_#{source_digest}_#{compile_source_map}"
77
+ result_json = cache.get(key)
78
+ return result_json if result_json
79
+ end
80
+ c = Opal::Compiler.new(source, compiler_options.merge(file: filename))
81
+ result = { 'javascript' => c.compile }
82
+ if compile_source_map
83
+ result['source_map'] = c.source_map.as_json
84
+ result['source_map']['file'] = filename
85
+ end
86
+ result['required_trees'] = c.required_trees
87
+ result_json = Oj.dump(result, mode: :strict)
88
+ cache.set(key, result_json) if cache
89
+ result_json
90
+ rescue Exception => e
91
+ Oj.dump({ 'error' => { 'name' => e.class.to_s, 'message' => e.message, 'backtrace' => e.backtrace.join("\n") } }, mode: :strict)
92
+ end
93
+ end
94
+
95
+ if ARGV[0] == 'start'
96
+ number_of_instances = ARGV[1].to_i
97
+ number_of_instances == 4 if number_of_instances == 0
98
+ else
99
+ raise 'arguments must be either "stop" or "start number_of_instances"'
100
+ exit(1)
101
+ end
102
+
103
+ load_paths = OpalWebpackLoader::LoadPathManager.read_load_paths_cache(compile_server_options[:load_paths_cache])
104
+ if load_paths
105
+ Opal.append_paths(*load_paths)
106
+ end
107
+
108
+ begin
109
+ OpalWebpackLoader::PipeServer.new(compile_server_options[:pipe_name], number_of_instances) do |request|
110
+ if request
111
+ if request.start_with?('command:stop')
112
+ STDERR.puts "Exiting with drama."
113
+ exit(0)
114
+ else
115
+ result = compile(request, cache, compiler_options)
116
+ result
117
+ end
118
+ end
119
+ end.run
120
+ rescue Exception => e
121
+ STDERR.puts "opal-webpack-windows-compile-server couldn't start:"
122
+ STDERR.puts e.backtrace.join("\n")
123
+ STDERR.puts e.message
124
+ exit 1
125
+ end
data/bin/owl-compiler ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ require 'digest'
3
+ require 'oj'
4
+ require 'c_lexer'
5
+ require 'optparse'
6
+ require 'opal/paths'
7
+ require 'opal/source_map'
8
+ require 'opal/compiler'
9
+ require 'opal-webpack-loader/load_path_manager'
10
+
11
+ modules_to_require = []
12
+ compiler_options = {}
13
+ compile_server_options = {}
14
+
15
+ OptionParser.new do |opts|
16
+ opts.on('-r', '--require MODULE', 'Require the module before starting the compile server.') do |m|
17
+ modules_to_require << m
18
+ end
19
+
20
+ opts.on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i|
21
+ $:.unshift(File.expand_path(i))
22
+ end
23
+
24
+ opts.on('-d', '--dynamic-require-severity SEVERITY', 'Compiler option, one of: error, warning, ignore.') do |s|
25
+ if %w[error warning ignore].include?(s)
26
+ compiler_options[:dynamic_require_severity] = s.to_sym
27
+ end
28
+ end
29
+
30
+ opts.on('-t', '--true FLAG', 'Set compiler flag to true.' ) do |f|
31
+ compiler_options[f.to_sym] = true
32
+ end
33
+
34
+ opts.on('-f', '--false FLAG', 'Set compiler flag to false.' ) do |f|
35
+ compiler_options[f.to_sym] = false
36
+ end
37
+
38
+ opts.on('-l', '--load-paths-cache PATH', 'Path to load path cache json') do |l|
39
+ compile_server_options[:load_paths_cache] = l
40
+ end
41
+
42
+ opts.on('-s', '--source-file PATH', 'Path of the file to compile.') do |s|
43
+ compile_server_options[:source_file] = s
44
+ end
45
+
46
+ opts.on('-c', '--create-map', 'Create source map.') do
47
+ compiler_server_options[:source_map] = true
48
+ end
49
+
50
+ opts.on('-m', '--memcached URL', 'URL of memcached server. Will enable use of memcached for caching compiler results.') do |m|
51
+ require 'dalli'
52
+ compile_server_options[:memcached] = m
53
+ compile_server_options[:cache] = Dalli::Client.new(compile_server_options[:memchached])
54
+ end
55
+
56
+ opts.on('-e', '--redis URL', 'URL of redis server. Will enable use of redis for caching compiler results.') do |e|
57
+ require 'redis'
58
+ compile_server_options[:redis] = e
59
+ compile_server_options[:cache] = Redis.new(url: other_options[:redis])
60
+ end
61
+ end.parse!
62
+
63
+ modules_to_require.each do |mod|
64
+ require mod
65
+ end
66
+
67
+ load_paths = OpalWebpackLoader::LoadPathManager.read_load_paths_cache(compile_server_options[:load_paths_cache])
68
+ if load_paths
69
+ Opal.append_paths(*load_paths)
70
+ end
71
+
72
+ compile_source_map = compile_server_options[:source_map]
73
+ filename = compile_server_options[:source_file]
74
+ source = File.read(filename)
75
+ compiler_options.merge!(es6_modules: true)
76
+ compiler_options.merge!(file: filename)
77
+
78
+ begin
79
+ if compile_server_options[:cache]
80
+ source_digest = Digest::SHA1.hexdigest(source)
81
+ key = "owl_#{compiler_options_digest}_#{source_digest}_#{compile_source_map}"
82
+ result_json = compile_server_options[:cache].get(key)
83
+ if result_json
84
+ STDOUT.puts result_json
85
+ exit 0
86
+ end
87
+ end
88
+ c = Opal::Compiler.new(source, compiler_options)
89
+ result = { 'javascript' => c.compile }
90
+ if compile_source_map
91
+ result['source_map'] = c.source_map.as_json
92
+ result['source_map']['file'] = filename
93
+ end
94
+ result['required_trees'] = c.required_trees
95
+ result_json = Oj.dump(result, mode: :strict)
96
+ compile_server_options[:cache].set(key, result_json) if compile_server_options[:cache]
97
+ STDOUT.puts result_json
98
+ rescue Exception => e
99
+ STDOUT.puts Oj.dump({ 'error' => { 'name' => e.class.to_s, 'message' => e.message, 'backtrace' => e.backtrace.join("\n") } }, mode: :strict)
100
+ end
File without changes
data/bin/owl-install CHANGED
File without changes
@@ -39,10 +39,13 @@ OpalWebpackLoader.client_asset_path = 'http://localhost:3035/assets/'
39
39
  OpalWebpackLoader.use_manifest = false
40
40
 
41
41
  # TODO require yarn instead of npm
42
- # TODO don't depend on which for non unixes
43
- npm = `which npm`.chop
42
+ npm = if Gem.win_platform?
43
+ `where npm`.chop.lines.last
44
+ else
45
+ `which npm`.chop
46
+ end
44
47
 
45
- if npm != ''
48
+ if !npm.nil? && !npm.empty?
46
49
  bin_dir = `npm bin`.chop
47
50
  begin
48
51
  owl_npm_version = `#{File.join(bin_dir, 'opal-webpack-loader-npm-version')}`.chop
@@ -0,0 +1,219 @@
1
+ require 'ffi'
2
+
3
+ module OpalWebpackLoader
4
+ module WindowsyThings
5
+ extend FFI::Library
6
+
7
+ ffi_lib :kernel32, :user32
8
+
9
+ ERROR_IO_PENDING = 997
10
+ ERROR_PIPE_CONNECTED = 535
11
+ ERROR_SUCCESS = 0
12
+
13
+ FILE_FLAG_OVERLAPPED = 0x40000000
14
+
15
+ INFINITE = 0xFFFFFFFF
16
+ INVALID_HANDLE_VALUE = FFI::Pointer.new(-1).address
17
+
18
+ PIPE_ACCESS_DUPLEX = 0x00000003
19
+ PIPE_READMODE_BYTE = 0x00000000
20
+ PIPE_READMODE_MESSAGE = 0x00000002
21
+ PIPE_TYPE_BYTE = 0x00000000
22
+ PIPE_TYPE_MESSAGE = 0x00000004
23
+ PIPE_WAIT = 0x00000000
24
+
25
+ QS_ALLINPUT = 0x04FF
26
+
27
+ typedef :uintptr_t, :handle
28
+
29
+ attach_function :ConnectNamedPipe, [:handle, :pointer], :ulong
30
+ attach_function :CreateEvent, :CreateEventA, [:pointer, :ulong, :ulong, :string], :handle
31
+ attach_function :CreateNamedPipe, :CreateNamedPipeA, [:string, :ulong, :ulong, :ulong, :ulong, :ulong, :ulong, :pointer], :handle
32
+ attach_function :DisconnectNamedPipe, [:handle], :bool
33
+ attach_function :FlushFileBuffers, [:handle], :bool
34
+ attach_function :GetLastError, [], :ulong
35
+ attach_function :GetOverlappedResult, [:handle, :pointer, :pointer, :bool], :bool
36
+ attach_function :MsgWaitForMultipleObjects, [:ulong, :pointer, :ulong, :ulong, :ulong], :ulong
37
+ attach_function :ReadFile, [:handle, :buffer_out, :ulong, :pointer, :pointer], :bool
38
+ attach_function :SetEvent, [:handle], :bool
39
+ attach_function :WaitForMultipleObjects, [:ulong, :pointer, :ulong, :ulong], :ulong
40
+ attach_function :WriteFile, [:handle, :buffer_in, :ulong, :pointer, :pointer], :bool
41
+ end
42
+
43
+ class PipeServer
44
+ include OpalWebpackLoader::WindowsyThings
45
+
46
+ CONNECTING_STATE = 0
47
+ READING_STATE = 1
48
+ WRITING_STATE = 2
49
+ INSTANCES = 4
50
+ PIPE_TIMEOUT = 5000
51
+ BUFFER_SIZE = 65536
52
+
53
+ class Overlapped < FFI::Struct
54
+ layout(
55
+ :Internal, :uintptr_t,
56
+ :InternalHigh, :uintptr_t,
57
+ :Offset, :ulong,
58
+ :OffsetHigh, :ulong,
59
+ :hEvent, :uintptr_t
60
+ )
61
+ end
62
+
63
+ def initialize(pipe_name, instances = 4, &block)
64
+ @run_block = block
65
+ @full_pipe_name = "\\\\.\\pipe\\#{pipe_name}"
66
+ @instances = instances
67
+ @events = []
68
+ @events_pointer = FFI::MemoryPointer.new(:uintptr_t, @instances)
69
+ @pipes = []
70
+ end
71
+
72
+ def run
73
+ create_instances
74
+ while_loop
75
+ end
76
+
77
+ private
78
+
79
+ def create_instances
80
+ (0...@instances).each do |i|
81
+ @events[i] = CreateEvent(nil, 1, 1, nil)
82
+ raise "CreateEvent failed with #{GetLastError()}" unless @events[i]
83
+
84
+ overlap = Overlapped.new
85
+ overlap[:hEvent] = @events[i]
86
+
87
+ @pipes[i] = { overlap: overlap, instance: nil, request: FFI::Buffer.new(1, BUFFER_SIZE), bytes_read: 0, reply: FFI::Buffer.new(1, BUFFER_SIZE), bytes_to_write: 0, state: nil, pending_io: false }
88
+ @pipes[i][:instance] = CreateNamedPipe(@full_pipe_name,
89
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
90
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
91
+ @instances,
92
+ BUFFER_SIZE,
93
+ BUFFER_SIZE,
94
+ PIPE_TIMEOUT,
95
+ nil)
96
+
97
+ raise "CreateNamedPipe failed with #{GetLastError()}" if @pipes[i][:instance] == INVALID_HANDLE_VALUE
98
+ @pipes[i][:pending_io] = connect_to_new_client(i)
99
+ @pipes[i][:state] = @pipes[i][:pending_io] ? CONNECTING_STATE : READING_STATE
100
+ end
101
+ @events_pointer.write_array_of_ulong_long(@events)
102
+ nil
103
+ end
104
+
105
+ def while_loop
106
+ while true
107
+ i = MsgWaitForMultipleObjects(@instances, @events_pointer, 0, INFINITE, QS_ALLINPUT)
108
+ # Having this STDOUT.putc is essential, otherwise there is a tendency to block within MsgWaitForMultipleObjects ...
109
+ STDOUT.putc "."
110
+ # ... because the ruby interpreter is waiting for objects too on Windows. Thats why we wait for QS_ALLINPUT and
111
+ # with STDOUT.putc give back control to the ruby interpreter that it can handle its things.
112
+ if i < 0 || i > (@instances - 1)
113
+ STDERR.puts "Pipe index out of range. Maybe a error occured."
114
+ next
115
+ end
116
+
117
+ if @pipes[i][:pending_io]
118
+ bytes_transferred = FFI::MemoryPointer.new(:ulong)
119
+ success = GetOverlappedResult(@pipes[i][:instance], @pipes[i][:overlap], bytes_transferred, false)
120
+
121
+ case @pipes[i][:state]
122
+ when CONNECTING_STATE
123
+ raise "Error #{GetLastError()}" unless success
124
+ @pipes[i][:state] = READING_STATE
125
+ when READING_STATE
126
+ if !success || bytes_transferred.read_ulong == 0
127
+ disconnect_and_reconnect(i)
128
+ next
129
+ else
130
+ @pipes[i][:bytes_read] = bytes_transferred.read_ulong
131
+ @pipes[i][:state] = WRITING_STATE
132
+ end
133
+ when WRITING_STATE
134
+ if !success || bytes_transferred.read_ulong != @pipes[i][:bytes_to_write]
135
+ disconnect_and_reconnect(i)
136
+ next
137
+ else
138
+ @pipes[i][:state] = READING_STATE
139
+ end
140
+ else
141
+ raise "Invalid pipe state."
142
+ end
143
+ end
144
+
145
+ case @pipes[i][:state]
146
+ when READING_STATE
147
+ bytes_read = FFI::MemoryPointer.new(:ulong)
148
+ success = ReadFile(@pipes[i][:instance], @pipes[i][:request], BUFFER_SIZE, bytes_read, @pipes[i][:overlap].to_ptr)
149
+ if success && bytes_read.read_ulong != 0
150
+ @pipes[i][:pending_io] = false
151
+ @pipes[i][:state] = WRITING_STATE
152
+ next
153
+ end
154
+
155
+ err = GetLastError()
156
+ if !success && err == ERROR_IO_PENDING
157
+ @pipes[i][:pending_io] = true
158
+ next
159
+ end
160
+
161
+ disconnect_and_reconnect(i)
162
+ when WRITING_STATE
163
+ @pipes[i][:reply] = @run_block.call(@pipes[i][:request].get_string(0))
164
+ @pipes[i][:bytes_to_write] = @pipes[i][:reply].bytesize
165
+ bytes_written = FFI::MemoryPointer.new(:ulong)
166
+ success = WriteFile(@pipes[i][:instance], @pipes[i][:reply], @pipes[i][:bytes_to_write], bytes_written, @pipes[i][:overlap].to_ptr)
167
+
168
+ if success && bytes_written.read_ulong == @pipes[i][:bytes_to_write]
169
+ @pipes[i][:pending_io] = false
170
+ @pipes[i][:state] = READING_STATE
171
+ next
172
+ end
173
+
174
+ err = GetLastError()
175
+
176
+ if !success && err == ERROR_IO_PENDING
177
+ @pipes[i][:pending_io] = true
178
+ next
179
+ end
180
+
181
+ disconnect_and_reconnect(i)
182
+ else
183
+ raise "Invalid pipe state."
184
+ end
185
+ end
186
+ end
187
+
188
+ def disconnect_and_reconnect(i)
189
+ FlushFileBuffers(@pipes[i][:instance])
190
+ STDERR.puts("DisconnectNamedPipe failed with #{GetLastError()}") if !DisconnectNamedPipe(@pipes[i][:instance])
191
+
192
+ @pipes[i][:pending_io] = connect_to_new_client(i)
193
+
194
+ @pipes[i][:state] = @pipes[i][:pending_io] ? CONNECTING_STATE : READING_STATE
195
+ end
196
+
197
+ def connect_to_new_client(i)
198
+ pending_io = false
199
+ @pipes[i][:request].clear
200
+ @pipes[i][:reply].clear
201
+ connected = ConnectNamedPipe(@pipes[i][:instance], @pipes[i][:overlap].to_ptr)
202
+ last_error = GetLastError()
203
+ raise "ConnectNamedPipe failed with #{last_error} - #{connected}" if connected != 0
204
+
205
+ case last_error
206
+ when ERROR_IO_PENDING
207
+ pending_io = true
208
+ when ERROR_PIPE_CONNECTED
209
+ SetEvent(@pipes[i][:overlap][:hEvent])
210
+ when ERROR_SUCCESS
211
+ pending_io = true
212
+ else
213
+ raise "ConnectNamedPipe failed with error #{last_error}"
214
+ end
215
+
216
+ pending_io
217
+ end
218
+ end
219
+ end
@@ -9,4 +9,6 @@ else
9
9
  OpalWebpackLoader.manifest_path = nil
10
10
  OpalWebpackLoader.use_manifest = false
11
11
  end
12
- <%= opal_load_path %>
12
+ <%= opal_load_path %>
13
+
14
+ Rails.autoloaders.main.ignore "#{__dir__}/../../app/opal" if Dir.exist? "#{__dir__}/../../app/opal"
@@ -9,18 +9,18 @@
9
9
  "production_build": "<%= production_script %>"
10
10
  },
11
11
  "devDependencies": {
12
- "compression-webpack-plugin": "^3.0.0",
13
- "css-loader": "^3.2.0",
12
+ "compression-webpack-plugin": "^5.0.2",
13
+ "css-loader": "^5.2.4",
14
14
  "extra-watch-webpack-plugin": "^1.0.3",
15
- "file-loader": "^5.0.2",
16
- "node-sass": "^4.13.0",
17
- "parallel-webpack": "^2.4.0",
18
- "sass-loader": "^8.0.0",
19
- "style-loader": "^1.0.0",
20
- "terser-webpack-plugin": "^2.2.1",
21
- "webpack": "^4.41.2",
22
- "webpack-assets-manifest": "^3.1.1",
23
- "webpack-cli": "^3.3.10",
24
- "webpack-dev-server": "^3.9.0"
15
+ "file-loader": "^6.2.0",
16
+ "node-sass": "^6.0.0",
17
+ "parallel-webpack": "^2.6.0",
18
+ "sass-loader": "^10.0.5",
19
+ "style-loader": "^2.0.0",
20
+ "terser-webpack-plugin": "^4.2.3",
21
+ "webpack": "^4.46.0",
22
+ "webpack-assets-manifest": "^4.0.6",
23
+ "webpack-cli": "^4.7.0",
24
+ "webpack-dev-server": "^3.11.2"
25
25
  }
26
26
  }
@@ -9,7 +9,7 @@ const common_config = {
9
9
  mode: "production",
10
10
  optimization: {
11
11
  minimize: true, // minimize
12
- minimizer: [new TerserPlugin({ parallel: true, cache: true })]
12
+ minimizer: [new TerserPlugin({ parallel: true })]
13
13
  },
14
14
  performance: {
15
15
  maxAssetSize: 20000000,
@@ -26,8 +26,8 @@ const common_config = {
26
26
  ]
27
27
  },
28
28
  plugins: [
29
- new CompressionPlugin({ test: /^((?!application_ssr).)*$/, cache: true }), // gzip compress, exclude application_ssr.js
30
- new WebpackAssetsManifest({ publicPath: true, merge: true }) // generate manifest
29
+ new CompressionPlugin({ test: /^((?!application_ssr).)*$/ }), // gzip compress, exclude application_ssr.js
30
+ new WebpackAssetsManifest({ publicPath: true, merge: true, output: 'manifest.json' }) // generate manifest
31
31
  ],
32
32
  module: {
33
33
  rules: [
@@ -1,3 +1,3 @@
1
- module OpalWebpackLoader
2
- VERSION="0.9.11"
3
- end
1
+ module OpalWebpackLoader
2
+ VERSION="0.11.0"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-webpack-loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.11
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-01 00:00:00.000000000 Z
11
+ date: 2021-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -52,34 +52,48 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.7.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: ffi
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.15.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.15.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: oj
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: 3.7.0
75
+ version: 3.11.0
62
76
  type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
- version: 3.7.0
82
+ version: 3.11.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: redis
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: 4.1.0
89
+ version: 4.2.0
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: 4.1.0
96
+ version: 4.2.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: thor
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -142,28 +156,28 @@ dependencies:
142
156
  requirements:
143
157
  - - "~>"
144
158
  - !ruby/object:Gem::Version
145
- version: 5.2.3
159
+ version: 6.1.0
146
160
  type: :development
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
- version: 5.2.3
166
+ version: 6.1.0
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: roda
155
169
  requirement: !ruby/object:Gem::Requirement
156
170
  requirements:
157
171
  - - "~>"
158
172
  - !ruby/object:Gem::Version
159
- version: 3.19.0
173
+ version: 3.43.0
160
174
  type: :development
161
175
  prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
178
  - - "~>"
165
179
  - !ruby/object:Gem::Version
166
- version: 3.19.0
180
+ version: 3.43.0
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: rspec
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +198,14 @@ dependencies:
184
198
  requirements:
185
199
  - - ">="
186
200
  - !ruby/object:Gem::Version
187
- version: 4.0.0
201
+ version: 5.3.0
188
202
  type: :development
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
206
  - - ">="
193
207
  - !ruby/object:Gem::Version
194
- version: 4.0.0
208
+ version: 5.3.0
195
209
  description: "Bundle assets with webpack, resolve and compile opal ruby files\nand
196
210
  import them in the bundle, without sprockets or the webpacker gem\n(but can be used
197
211
  with both of them too). \nComes with a installer for rails and other frameworks.\n"
@@ -200,11 +214,16 @@ executables:
200
214
  - opal-webpack-compile-server
201
215
  - owl-install
202
216
  - owl-gen-loadpath-cache
217
+ - owl-compiler
218
+ - opal-webpack-windows-compile-server
203
219
  extensions: []
204
220
  extra_rdoc_files: []
205
221
  files:
206
222
  - LICENSE
223
+ - README.md
207
224
  - bin/opal-webpack-compile-server
225
+ - bin/opal-webpack-windows-compile-server
226
+ - bin/owl-compiler
208
227
  - bin/owl-gen-loadpath-cache
209
228
  - bin/owl-install
210
229
  - lib/opal-webpack-loader.rb
@@ -213,6 +232,7 @@ files:
213
232
  - lib/opal-webpack-loader/installer_cli.rb
214
233
  - lib/opal-webpack-loader/load_path_manager.rb
215
234
  - lib/opal-webpack-loader/manifest.rb
235
+ - lib/opal-webpack-loader/pipe_server.rb
216
236
  - lib/opal-webpack-loader/rails_view_helper.rb
217
237
  - lib/opal-webpack-loader/templates/Procfile.erb
218
238
  - lib/opal-webpack-loader/templates/app_loader.rb.erb
@@ -237,7 +257,7 @@ licenses:
237
257
  - MIT
238
258
  metadata:
239
259
  github_repo: ssh://github.com/isomorfeus/gems
240
- post_install_message:
260
+ post_install_message:
241
261
  rdoc_options: []
242
262
  require_paths:
243
263
  - lib
@@ -252,8 +272,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
252
272
  - !ruby/object:Gem::Version
253
273
  version: '0'
254
274
  requirements: []
255
- rubygems_version: 3.0.6
256
- signing_key:
275
+ rubygems_version: 3.2.15
276
+ signing_key:
257
277
  specification_version: 4
258
278
  summary: Bundle assets with webpack, resolve and compile opal ruby files and import
259
279
  them in the bundle.