pakyow-assets 0.1.2 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +3 -19
  3. data/lib/pakyow/assets.rb +19 -0
  4. data/lib/pakyow/assets/actions/process.rb +63 -0
  5. data/lib/pakyow/assets/actions/public.rb +75 -0
  6. data/lib/pakyow/assets/asset.rb +238 -0
  7. data/lib/pakyow/assets/babel.rb +34 -0
  8. data/lib/pakyow/assets/behavior/assets.rb +45 -0
  9. data/lib/pakyow/assets/behavior/config.rb +137 -0
  10. data/lib/pakyow/assets/behavior/externals.rb +58 -0
  11. data/lib/pakyow/assets/behavior/packs.rb +162 -0
  12. data/lib/pakyow/assets/behavior/prelaunching.rb +19 -0
  13. data/lib/pakyow/assets/behavior/processing.rb +27 -0
  14. data/lib/pakyow/assets/behavior/rendering/install_assets.rb +39 -0
  15. data/lib/pakyow/assets/behavior/silencing.rb +35 -0
  16. data/lib/pakyow/assets/behavior/watching.rb +25 -0
  17. data/lib/pakyow/assets/errors.rb +16 -0
  18. data/lib/pakyow/assets/external.rb +103 -0
  19. data/lib/pakyow/assets/framework.rb +52 -0
  20. data/lib/pakyow/assets/pack.rb +171 -0
  21. data/lib/pakyow/assets/precompiler.rb +63 -0
  22. data/lib/pakyow/assets/source_map.rb +99 -0
  23. data/lib/pakyow/assets/tasks/precompile.rake +9 -0
  24. data/lib/pakyow/assets/tasks/update.rake +20 -0
  25. data/lib/pakyow/assets/types/css.rb +45 -0
  26. data/lib/pakyow/assets/types/js.rb +98 -0
  27. data/lib/pakyow/assets/types/sass.rb +69 -0
  28. data/lib/pakyow/assets/types/scss.rb +14 -0
  29. data/src/@babel/standalone@7.3.1/babel.min.js +165 -0
  30. data/src/@babel/standalone@7.4.5/babel.min.js +92359 -0
  31. metadata +146 -46
  32. data/CHANGELOG.md +0 -18
  33. data/README.md +0 -58
  34. data/lib/assets.rb +0 -221
  35. data/lib/config.rb +0 -37
  36. data/lib/middleware.rb +0 -42
  37. data/lib/pakyow-assets.rb +0 -31
  38. data/lib/preprocessors/css-preprocessor.rb +0 -16
  39. data/lib/preprocessors/image-preprocessor.rb +0 -1
  40. data/lib/preprocessors/javascript-preprocessor.rb +0 -16
  41. data/lib/preprocessors/sass-preprocessor.rb +0 -23
  42. data/lib/version.rb +0 -5
  43. data/pakyow-assets.gemspec +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c322853e853a355500e4b045b22acbcbec3c8925
4
- data.tar.gz: 29ce5c954d0d4c71025efdd12dfe70548155a9be
2
+ SHA256:
3
+ metadata.gz: bfdfa0ac5ee2f817f474ac114dc81491ff8dbaa4bbbc7a4a15b2020c5c102bd6
4
+ data.tar.gz: 57af0c11222e8c0ed16e6a3c18627f6d9971d395919cf199b5f13d4b348b0817
5
5
  SHA512:
6
- metadata.gz: 3e8c251d6f988046ff36e19bfef1200d4d5eefdb3d5009eb1eca1e02652f519e7567d0284400212b1178c2b826fd9eae8febacdefed5a2afa30fc621746c5dba
7
- data.tar.gz: 760555a99ee7ee4ba3078831066c40aec304b3ac455eb4228b56107cbd544a8d507e12a0e706df66f6186077e954caf51929d1b2fd67e127b6231a536f5bd7ca
6
+ metadata.gz: 293fbdf6b36ad59ff7c046374c899c9ba26aab45ff365175e90dc3f2ce8ddd385ae0d8c47909721efa16ddad9d66e9e5fae09884737258bfb167a3dd57ee2124
7
+ data.tar.gz: 443a19539eff33d4650568901ee1244453b2aa2e36b996202572846dd5fad51980fb567494f421b04de9405833a50a93ece963a18a3f3a842a8656395f256e82
data/LICENSE CHANGED
@@ -1,20 +1,4 @@
1
- Copyright (c) 2015 Bryan Powell
1
+ Copyright (c) Metabahn, LLC
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3
+ Pakyow Assets is an open-source project licensed under the terms of the LGPLv3 license.
4
+ See <https://choosealicense.com/licenses/lgpl-3.0/> for license text.
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/routing"
4
+ require "pakyow/support"
5
+ require "pakyow/presenter"
6
+
7
+ require "pakyow/assets/framework"
8
+
9
+ require "pakyow/assets/actions/process"
10
+ require "pakyow/assets/actions/public"
11
+
12
+ require "pakyow/assets/types/js"
13
+ require "pakyow/assets/types/css"
14
+ require "pakyow/assets/types/sass"
15
+ require "pakyow/assets/types/scss"
16
+
17
+ module Pakyow
18
+ config.tasks.paths << File.expand_path("../assets/tasks", __FILE__)
19
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pakyow
4
+ module Assets
5
+ module Actions
6
+ # Pipeline Action that processes assets at request time.
7
+ #
8
+ # This is intended for development use, please don't use it in production.
9
+ # Instead, precompile assets into the public directory.
10
+ #
11
+ class Process
12
+ def call(connection)
13
+ if connection.app.config.assets.process
14
+ # TODO: can we short circuit if the request path doesn't match the connection?
15
+ if asset = find_asset(connection) || find_pack(connection) || find_asset_map(connection) || find_pack_map(connection)
16
+ connection.set_header("content-type", asset.mime_type)
17
+ connection.body = asset
18
+ connection.halt
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def find_asset(connection, path = connection.path)
26
+ connection.app.state(:asset).find { |asset|
27
+ asset.public_path == path
28
+ }
29
+ end
30
+
31
+ def find_pack(connection, path = connection.path)
32
+ connection.app.state(:pack).lazy.map { |pack|
33
+ pack.packed(path)
34
+ }.find { |packed| !packed.nil? && packed.any? }
35
+ end
36
+
37
+ def find_asset_map(connection)
38
+ if wants_map?(connection)
39
+ if (asset = find_asset(connection, unmapped(connection))) && asset.source_map?
40
+ asset.source_map
41
+ end
42
+ end
43
+ end
44
+
45
+ def find_pack_map(connection)
46
+ if (pack = find_pack(connection, unmapped(connection))) && pack.source_map?
47
+ pack.source_map
48
+ else
49
+ nil
50
+ end
51
+ end
52
+
53
+ def wants_map?(connection)
54
+ connection.path.end_with?(".map")
55
+ end
56
+
57
+ def unmapped(connection)
58
+ File.join(File.dirname(connection.path), File.basename(connection.path, ".map"))
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mini_mime"
4
+
5
+ require "pakyow/support/core_refinements/string/normalization"
6
+
7
+ module Pakyow
8
+ module Assets
9
+ module Actions
10
+ class Public
11
+ using Support::Refinements::String::Normalization
12
+
13
+ # Pipeline Action that serves files out of your public directory.
14
+ #
15
+ def initialize(app)
16
+ @asset_paths = app.state(:asset).map(&:public_path) + app.state(:pack).flat_map { |pack|
17
+ [pack.public_css_path, pack.public_js_path]
18
+ }
19
+
20
+ @prefix = if app.is_a?(Plugin)
21
+ Pathname.new(app.class.mount_path)
22
+ else
23
+ Pathname.new("/")
24
+ end
25
+ end
26
+
27
+ def call(connection)
28
+ if connection.app.config.assets.public
29
+ public_path = public_path(connection)
30
+
31
+ if public?(public_path)
32
+ if mime = MiniMime.lookup_by_filename(public_path)
33
+ connection.set_header("content-type", mime.content_type)
34
+ end
35
+
36
+ if connection.app.config.assets.cache && asset?(connection)
37
+ set_cache_headers(connection, public_path)
38
+ end
39
+
40
+ connection.body = File.open(public_path)
41
+ connection.halt
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def public?(path)
49
+ File.file?(path)
50
+ end
51
+
52
+ def public_path(connection)
53
+ File.join(
54
+ connection.app.config.assets.public_path,
55
+ String.normalize_path(
56
+ Pathname.new(connection.path).relative_path_from(@prefix).to_s
57
+ )
58
+ )
59
+ end
60
+
61
+ def asset?(connection)
62
+ @asset_paths.include?(connection.path)
63
+ end
64
+
65
+ def set_cache_headers(connection, public_path)
66
+ mtime = File.mtime(public_path)
67
+ connection.set_header("age", (Time.now - mtime).to_i.to_s)
68
+ connection.set_header("cache-control", "public, max-age=31536000")
69
+ connection.set_header("vary", "accept-encoding")
70
+ connection.set_header("last-modified", mtime.httpdate)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+
5
+ require "pakyow/support/class_state"
6
+ require "pakyow/support/core_refinements/string/normalization"
7
+
8
+ require "pakyow/assets/source_map"
9
+
10
+ module Pakyow
11
+ module Assets
12
+ # Represents an asset.
13
+ #
14
+ # Instances are created when booting in all environments, meaning the app
15
+ # is guaranteed access to these objects. Contents are loaded and processed
16
+ # eagerly. This is expected to happen under two scenarios:
17
+ #
18
+ # 1. In development, an asset is loaded and processed when it's requested.
19
+ # 2. In production, when assets are precompiled during a deployment.
20
+ #
21
+ class Asset
22
+ using Support::Refinements::String::Normalization
23
+
24
+ extend Support::ClassState
25
+ class_state :__types, default: []
26
+ class_state :__emits, default: nil
27
+ class_state :__extensions, default: [], inheritable: true
28
+ class_state :__minifiable, default: false, inheritable: true
29
+
30
+ class << self
31
+ def new_from_path(path, config:, source_location: "", prefix: "/", related: [])
32
+ asset_class = @__types.find { |type|
33
+ type.__extensions.include?(File.extname(path))
34
+ } || self
35
+
36
+ asset_class.load; asset_class.new(
37
+ local_path: path,
38
+ source_location: source_location,
39
+ config: config,
40
+ prefix: prefix,
41
+ related: related
42
+ )
43
+ end
44
+
45
+ # Implemented by subclasses to load any libraries they need.
46
+ #
47
+ def load
48
+ # intentionally empty
49
+ end
50
+
51
+ # @api private
52
+ def inherited(asset_class)
53
+ @__types << asset_class
54
+ super
55
+ end
56
+
57
+ # @api private
58
+ def update_path_for_emitted_type(path)
59
+ if @__emits
60
+ path.sub(File.extname(path), @__emits)
61
+ else
62
+ path
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ # Registers +extension+ for this asset.
69
+ #
70
+ def extension(extension)
71
+ extensions(extension)
72
+ end
73
+
74
+ # Registers multiple extensions for this asset.
75
+ #
76
+ def extensions(*extensions)
77
+ extensions.each do |extension|
78
+ @__extensions << ".#{extension}"
79
+ end
80
+ end
81
+
82
+ # Defines the emitted asset type (e.g. +sass+ emits +css+).
83
+ #
84
+ def emits(type)
85
+ @__emits = ".#{type}"
86
+ end
87
+ end
88
+
89
+ attr_reader :logical_path, :mime_type, :mime_suffix, :dependencies
90
+
91
+ def initialize(local_path:, config:, dependencies: [], source_location: "", prefix: "/", related: [])
92
+ @local_path, @config, @source_location, @dependencies, @related = local_path, config, source_location, dependencies, related
93
+
94
+ @logical_path = self.class.update_path_for_emitted_type(
95
+ String.normalize_path(
96
+ File.join(prefix, local_path.sub(source_location, ""))
97
+ )
98
+ )
99
+
100
+ @public_path = String.normalize_path(
101
+ File.join(config.prefix, @logical_path)
102
+ )
103
+
104
+ @mime_type = case File.extname(@public_path)
105
+ when ".js"
106
+ # Resolves an issue with mini_mime returning `application/ecmascript`
107
+ #
108
+ "application/javascript"
109
+ else
110
+ MiniMime.lookup_by_filename(@public_path)&.content_type.to_s
111
+ end
112
+
113
+ @mime_prefix, @mime_suffix = @mime_type.split("/", 2)
114
+
115
+ @source_map_enabled = config.source_maps
116
+
117
+ @mutex = Mutex.new
118
+ end
119
+
120
+ # Overriding and freezing after content is set lets us eagerly process the
121
+ # content rather than incurring that cost on boot.
122
+ #
123
+ def freeze
124
+ super if instance_variable_defined?(:@content)
125
+ end
126
+
127
+ def each(&block)
128
+ ensure_content do |content|
129
+ StringIO.new(post_process(content)).each(&block)
130
+ end
131
+ end
132
+
133
+ def read
134
+ String.new.tap do |asset|
135
+ each do |content|
136
+ asset << content
137
+ end
138
+ end
139
+ end
140
+
141
+ def bytesize
142
+ ensure_content(&:bytesize)
143
+ end
144
+
145
+ def fingerprint
146
+ [@local_path].concat(dependencies).each_with_object(Digest::MD5.new) { |path, digest|
147
+ digest.update(Digest::MD5.file(path).hexdigest)
148
+ }.hexdigest
149
+ end
150
+
151
+ def fingerprinted_filename
152
+ extension = File.extname(@public_path)
153
+ File.basename(@public_path, extension) + "__" + fingerprint + extension
154
+ end
155
+
156
+ def public_path
157
+ if @config.fingerprint
158
+ File.join(
159
+ File.dirname(@public_path),
160
+ fingerprinted_filename
161
+ )
162
+ else
163
+ @public_path
164
+ end
165
+ end
166
+
167
+ def source_map?
168
+ respond_to?(:source_map_content)
169
+ end
170
+
171
+ def source_map
172
+ if source_map?
173
+ SourceMap.new(
174
+ source_map_content,
175
+ file: File.basename(public_path)
176
+ )
177
+ else
178
+ nil
179
+ end
180
+ end
181
+
182
+ def disable_source_map
183
+ tap do
184
+ @source_map_enabled = false
185
+ end
186
+ end
187
+
188
+ private
189
+
190
+ def ensure_content
191
+ @mutex.synchronize do
192
+ unless frozen? || instance_variable_defined?(:@content)
193
+ @content = load_content; freeze
194
+ end
195
+ end
196
+
197
+ yield @content if block_given?
198
+ end
199
+
200
+ def load_content
201
+ content = process(File.read(@local_path)).to_s
202
+
203
+ if mime_suffix == "css" || mime_suffix == "javascript"
204
+ # Update references to related assets with prefixed path, fingerprints.
205
+ # Do this here rather than in post-processing so that the source maps reflect the changes.
206
+ #
207
+ @related.each do |asset|
208
+ if asset != self && content.include?(asset.logical_path)
209
+ content.gsub!(asset.logical_path, asset.public_path)
210
+ end
211
+ end
212
+ end
213
+
214
+ content
215
+ end
216
+
217
+ def process(content)
218
+ content
219
+ end
220
+
221
+ def post_process(content)
222
+ if @source_map_enabled && source_map?
223
+ embed_mapping_url(content)
224
+ else
225
+ content
226
+ end
227
+ end
228
+
229
+ def embed_mapping_url(content)
230
+ content + SourceMap.mapping_url(path: public_path, type: @mime_suffix)
231
+ end
232
+
233
+ def external?
234
+ File.dirname(@local_path) == @config.externals.path
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mini_racer"
4
+ require "execjs"
5
+
6
+ require "pakyow/support/inflector"
7
+
8
+ module Pakyow
9
+ module Assets
10
+ class Babel
11
+ def self.transform(content, **options)
12
+ context.call("Babel.transform", content, camelize_keys(options))
13
+ end
14
+
15
+ private
16
+
17
+ def self.context
18
+ @context ||= ExecJS.compile(
19
+ File.read(
20
+ File.expand_path("../../../../src/@babel/standalone@7.4.5/babel.min.js", __FILE__)
21
+ )
22
+ )
23
+ end
24
+
25
+ def self.camelize_keys(options)
26
+ Hash[options.map { |key, value|
27
+ key = Support.inflector.camelize(key)
28
+ key = key[0, 1].downcase + key[1..-1]
29
+ [key, value]
30
+ }]
31
+ end
32
+ end
33
+ end
34
+ end