vite_rails 1.0.11 → 2.0.3

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +52 -34
  4. data/lib/tasks/vite.rake +17 -0
  5. data/lib/vite_rails.rb +5 -82
  6. data/lib/vite_rails/config.rb +11 -130
  7. data/lib/vite_rails/engine.rb +7 -11
  8. data/lib/vite_rails/installation.rb +52 -0
  9. data/lib/vite_rails/tag_helpers.rb +61 -0
  10. data/lib/vite_rails/version.rb +2 -2
  11. data/{lib/install/config/vite.json → templates/config/rails-vite.json} +1 -0
  12. data/{lib/install/javascript → templates}/entrypoints/application.js +0 -0
  13. metadata +27 -166
  14. data/CONTRIBUTING.md +0 -33
  15. data/lib/install/bin/vite +0 -17
  16. data/lib/install/binstubs.rb +0 -6
  17. data/lib/install/config/vite.config.ts +0 -11
  18. data/lib/install/template.rb +0 -40
  19. data/lib/tasks/vite/binstubs.rake +0 -12
  20. data/lib/tasks/vite/build.rake +0 -39
  21. data/lib/tasks/vite/clean.rake +0 -23
  22. data/lib/tasks/vite/clobber.rake +0 -20
  23. data/lib/tasks/vite/info.rake +0 -20
  24. data/lib/tasks/vite/install.rake +0 -12
  25. data/lib/tasks/vite/install_dependencies.rake +0 -14
  26. data/lib/tasks/vite/verify_install.rake +0 -23
  27. data/lib/vite_rails/builder.rb +0 -111
  28. data/lib/vite_rails/commands.rb +0 -109
  29. data/lib/vite_rails/dev_server.rb +0 -23
  30. data/lib/vite_rails/dev_server_proxy.rb +0 -57
  31. data/lib/vite_rails/helper.rb +0 -71
  32. data/lib/vite_rails/manifest.rb +0 -140
  33. data/lib/vite_rails/runner.rb +0 -53
  34. data/package.json +0 -19
  35. data/package/default.vite.json +0 -16
  36. data/test/builder_test.rb +0 -77
  37. data/test/commands_test.rb +0 -67
  38. data/test/config_test.rb +0 -133
  39. data/test/dev_server_proxy_test.rb +0 -102
  40. data/test/dev_server_test.rb +0 -9
  41. data/test/engine_rake_tasks_test.rb +0 -81
  42. data/test/helper_test.rb +0 -70
  43. data/test/manifest_test.rb +0 -79
  44. data/test/mode_test.rb +0 -16
  45. data/test/mounted_app/Rakefile +0 -6
  46. data/test/mounted_app/test/dummy/Rakefile +0 -5
  47. data/test/mounted_app/test/dummy/bin/rails +0 -5
  48. data/test/mounted_app/test/dummy/bin/rake +0 -5
  49. data/test/mounted_app/test/dummy/config.ru +0 -7
  50. data/test/mounted_app/test/dummy/config/application.rb +0 -12
  51. data/test/mounted_app/test/dummy/config/environment.rb +0 -5
  52. data/test/mounted_app/test/dummy/config/vite.json +0 -14
  53. data/test/mounted_app/test/dummy/package.json +0 -8
  54. data/test/mounted_app/test/dummy/yarn.lock +0 -208
  55. data/test/rake_tasks_test.rb +0 -60
  56. data/test/runner_test.rb +0 -31
  57. data/test/test_app/Rakefile +0 -5
  58. data/test/test_app/app/frontend/entrypoints/application.js +0 -2
  59. data/test/test_app/bin/vite +0 -17
  60. data/test/test_app/config.ru +0 -7
  61. data/test/test_app/config/application.rb +0 -13
  62. data/test/test_app/config/environment.rb +0 -6
  63. data/test/test_app/config/vite.json +0 -18
  64. data/test/test_app/config/vite_additional_paths.json +0 -5
  65. data/test/test_app/config/vite_public_dir.json +0 -5
  66. data/test/test_app/package.json +0 -13
  67. data/test/test_app/public/vite-production/manifest.json +0 -22
  68. data/test/test_app/some.config.js +0 -0
  69. data/test/test_app/yarn.lock +0 -11
  70. data/test/test_helper.rb +0 -68
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Public: Allows to verify if a Vite development server is already running.
4
- class ViteRails::DevServer
5
- # Public: Configure dev server connection timeout (in seconds).
6
- # Example:
7
- # ViteRails.dev_server.connect_timeout = 1
8
- cattr_accessor(:connect_timeout) { 0.01 }
9
-
10
- def initialize(config)
11
- @config = config
12
- end
13
-
14
- # Public: Returns true if the Vite development server is reachable.
15
- def running?
16
- Socket.tcp(host, port, connect_timeout: connect_timeout).close
17
- true
18
- rescue StandardError
19
- false
20
- end
21
-
22
- delegate :host, :port, to: :@config
23
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack/proxy'
4
-
5
- # Public: Allows to relay asset requests to the Vite development server.
6
- class ViteRails::DevServerProxy < Rack::Proxy
7
- VITE_DEPENDENCY_PREFIX = '/@'
8
-
9
- def initialize(app = nil, options = {})
10
- @vite_rails = options.delete(:vite_rails) || ViteRails.instance
11
- options[:streaming] = false if Rails.env.test? && !options.key?(:streaming)
12
- super
13
- end
14
-
15
- # Rack: Intercept asset requests and send them to the Vite server.
16
- def perform_request(env)
17
- if vite_should_handle?(env) && dev_server_running?
18
- forward_to_vite_dev_server(env)
19
- super(env)
20
- else
21
- @app.call(env)
22
- end
23
- end
24
-
25
- private
26
-
27
- delegate :config, :dev_server_running?, to: :@vite_rails
28
-
29
- def rewrite_uri_for_vite(env)
30
- uri = env.fetch('REQUEST_URI') { [env['PATH_INFO'], env['QUERY_STRING']].reject(&:blank?).join('?') }
31
- .sub(vite_asset_url_prefix, '/')
32
- env['PATH_INFO'], env['QUERY_STRING'] = (env['REQUEST_URI'] = uri).split('?')
33
- end
34
-
35
- def forward_to_vite_dev_server(env)
36
- rewrite_uri_for_vite(env)
37
- env['HTTP_HOST'] = env['HTTP_X_FORWARDED_HOST'] = config.host
38
- env['HTTP_X_FORWARDED_SERVER'] = config.host_with_port
39
- env['HTTP_PORT'] = env['HTTP_X_FORWARDED_PORT'] = config.port.to_s
40
- env['HTTP_X_FORWARDED_PROTO'] = env['HTTP_X_FORWARDED_SCHEME'] = config.protocol
41
- env['HTTPS'] = env['HTTP_X_FORWARDED_SSL'] = 'off' unless config.https
42
- env['SCRIPT_NAME'] = ''
43
- end
44
-
45
- def vite_should_handle?(env)
46
- path, query, referer = env['PATH_INFO'], env['QUERY_STRING'], env['HTTP_REFERER']
47
- return true if path.start_with?(vite_asset_url_prefix) # Vite asset
48
- return true if path.start_with?(VITE_DEPENDENCY_PREFIX) # Packages and imports
49
- return true if query&.start_with?('t=') # Hot Reload for a stylesheet
50
- return true if query&.start_with?('import&') # Hot Reload for an imported entrypoint
51
- return true if referer && URI.parse(referer).path.start_with?(vite_asset_url_prefix) # Entry imported from another entry.
52
- end
53
-
54
- def vite_asset_url_prefix
55
- @vite_asset_url_prefix ||= "/#{ config.public_output_dir }/"
56
- end
57
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Public: Allows to render HTML tags for scripts and styles processed by Vite.
4
- module ViteRails::Helper
5
- DEFAULT_VITE_SKIP_PRELOAD_TAGS = Rails.gem_version < Gem::Version.new('5.2.0')
6
-
7
- # Public: Returns the current Vite Rails instance.
8
- def current_vite_instance
9
- ViteRails.instance
10
- end
11
-
12
- # Public: Renders a script tag for vite/client to enable HMR in development.
13
- def vite_client_tag
14
- return unless current_vite_instance.dev_server_running?
15
-
16
- content_tag('script', '', src: current_vite_instance.manifest.prefix_vite_asset('@vite/client'), type: 'module')
17
- end
18
-
19
- # Public: Resolves the path for the specified Vite asset.
20
- #
21
- # Example:
22
- # <%= vite_asset_path 'calendar.css' %> # => "/vite/assets/calendar-1016838bab065ae1e122.css"
23
- def vite_asset_path(name, **options)
24
- path_to_asset current_vite_instance.manifest.lookup!(name, **options).fetch('file')
25
- end
26
-
27
- # Public: Renders a <script> tag for the specified Vite entrypoints.
28
- def vite_javascript_tag(*names,
29
- type: 'module',
30
- asset_type: :javascript,
31
- skip_preload_tags: DEFAULT_VITE_SKIP_PRELOAD_TAGS,
32
- skip_style_tags: false,
33
- crossorigin: 'anonymous',
34
- **options)
35
- js_entries = names.map { |name| current_vite_instance.manifest.lookup!(name, type: asset_type) }
36
- js_tags = javascript_include_tag(*js_entries.map { |entry| entry['file'] }, crossorigin: crossorigin, type: type, **options)
37
-
38
- unless skip_preload_tags || current_vite_instance.dev_server_running?
39
- preload_paths = js_entries.flat_map { |entry| entry['imports'] }.compact.uniq
40
- preload_tags = preload_paths.map { |path| preload_link_tag(path, crossorigin: crossorigin) }
41
- end
42
-
43
- unless skip_style_tags || current_vite_instance.dev_server_running?
44
- style_paths = names.map { |name|
45
- current_vite_instance.manifest.lookup(name.delete_suffix('.js'), type: :stylesheet)&.fetch('file')
46
- }.compact
47
- style_tags = stylesheet_link_tag(*style_paths)
48
- end
49
-
50
- safe_join [js_tags, preload_tags, style_tags]
51
- end
52
-
53
- # Public: Renders a <script> tag for the specified Vite entrypoints.
54
- #
55
- # NOTE: Because TypeScript is not a valid target in browsers, we only specify
56
- # the ts file when running the Vite development server.
57
- def vite_typescript_tag(*names, **options)
58
- vite_javascript_tag(*names, asset_type: :typescript, extname: false, **options)
59
- end
60
-
61
- # Public: Renders a <link> tag for the specified Vite entrypoints.
62
- def vite_stylesheet_tag(*names, **options)
63
- stylesheet_link_tag(*sources_from_vite_manifest(names, type: :stylesheet), **options)
64
- end
65
-
66
- private
67
-
68
- def sources_from_vite_manifest(names, type:)
69
- names.map { |name| vite_asset_path(name, type: type) }
70
- end
71
- end
@@ -1,140 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Public: Registry for accessing resources managed by Vite, using a generated
4
- # manifest file which maps entrypoint names to file paths.
5
- #
6
- # Example:
7
- # lookup_entrypoint('calendar', type: :javascript)
8
- # => { "file" => "/vite/assets/calendar-1016838bab065ae1e314.js", "imports" => [] }
9
- #
10
- # NOTE: Using "autoBuild": true` in `config/vite.json` file will trigger a build
11
- # on demand as needed, before performing any lookup.
12
- class ViteRails::Manifest
13
- class MissingEntryError < StandardError
14
- end
15
-
16
- def initialize(vite_rails)
17
- @vite_rails = vite_rails
18
- end
19
-
20
- # Public: Strict version of lookup.
21
- #
22
- # Returns a relative path for the asset, or raises an error if not found.
23
- def lookup!(*args, **options)
24
- lookup(*args, **options) || missing_entry_error(*args, **options)
25
- end
26
-
27
- # Public: Computes the path for a given Vite asset using manifest.json.
28
- #
29
- # Returns a relative path, or nil if the asset is not found.
30
- #
31
- # Example:
32
- # ViteRails.manifest.lookup('calendar.js')
33
- # # { "file" => "/vite/assets/calendar-1016838bab065ae1e122.js", "imports" => [] }
34
- def lookup(name, type: nil)
35
- build if should_build?
36
-
37
- find_manifest_entry(with_file_extension(name, type))
38
- end
39
-
40
- # Public: Refreshes the cached mappings by reading the updated manifest.
41
- def refresh
42
- @manifest = load_manifest
43
- end
44
-
45
- # Public: Scopes an asset to the output folder in public, as a path.
46
- def prefix_vite_asset(path)
47
- File.join("/#{ config.public_output_dir }", path)
48
- end
49
-
50
- private
51
-
52
- delegate :config, :builder, :dev_server_running?, to: :@vite_rails
53
-
54
- # NOTE: Auto compilation is convenient when running tests, when the developer
55
- # won't focus on the frontend, or when running the Vite server is not desired.
56
- def should_build?
57
- config.auto_build && !dev_server_running?
58
- end
59
-
60
- # Internal: Finds the specified entry in the manifest.
61
- def find_manifest_entry(name)
62
- if dev_server_running?
63
- { 'file' => prefix_vite_asset(name.to_s) }
64
- else
65
- manifest[name.to_s]
66
- end
67
- end
68
-
69
- # Internal: Performs a Vite build.
70
- def build
71
- ViteRails.logger.tagged('Vite') { builder.build }
72
- end
73
-
74
- # Internal: The parsed data from manifest.json.
75
- #
76
- # NOTE: When using build-on-demand in development and testing, the manifest
77
- # is reloaded automatically before each lookup, to ensure it's always fresh.
78
- def manifest
79
- return refresh if config.auto_build
80
-
81
- @manifest ||= load_manifest
82
- end
83
-
84
- # Internal: Returns a Hash with the entries in the manifest.json.
85
- def load_manifest
86
- if config.manifest_path.exist?
87
- JSON.parse(config.manifest_path.read).each do |_, entry|
88
- entry['file'] = prefix_vite_asset(entry['file'])
89
- entry['imports'] = entry['imports']&.map { |path| prefix_vite_asset(path) }
90
- end
91
- else
92
- {}
93
- end
94
- end
95
-
96
- # Internal: Adds a file extension to the file name, unless it already has one.
97
- def with_file_extension(name, entry_type)
98
- return name unless File.extname(name.to_s).empty?
99
-
100
- extension = extension_for_type(entry_type)
101
- extension ? "#{ name }.#{ extension }" : name
102
- end
103
-
104
- # Internal: Allows to receive :javascript and :stylesheet as :type in helpers.
105
- def extension_for_type(entry_type)
106
- case entry_type
107
- when :javascript then 'js'
108
- when :stylesheet then 'css'
109
- when :typescript then dev_server_running? ? 'ts' : 'js'
110
- else entry_type
111
- end
112
- end
113
-
114
- # Internal: Raises a detailed message when an entry is missing in the manifest.
115
- def missing_entry_error(name, type: nil, **_options)
116
- file_name = with_file_extension(name, type)
117
- raise ViteRails::Manifest::MissingEntryError, <<~MSG
118
- Vite Rails can't find #{ file_name } in #{ config.manifest_path }.
119
-
120
- Possible causes:
121
- #{ missing_entry_causes.map { |cause| "\t- #{ cause }" }.join("\n") }
122
-
123
- Your manifest contains:
124
- #{ JSON.pretty_generate(@manifest) }
125
- MSG
126
- end
127
-
128
- def missing_entry_causes
129
- local = config.auto_build
130
- [
131
- (dev_server_running? && 'Vite has not yet re-built your latest changes.'),
132
- (local && !dev_server_running? && "\"autoBuild\": false in your #{ config.mode } configuration."),
133
- (local && !dev_server_running? && 'The Vite development server has crashed or is no longer available.'),
134
- 'You have misconfigured config/vite.json file.',
135
- (!local && 'Assets have not been precompiled'),
136
- ].compact
137
- rescue StandardError
138
- []
139
- end
140
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Public: Executes Vite commands, providing conveniences for debugging.
4
- class ViteRails::Runner
5
- def initialize(argv)
6
- detect_unsupported_switches!(argv)
7
- @argv = argv
8
- end
9
-
10
- # Public: Executes Vite with the specified arguments.
11
- def run
12
- execute_command(@argv.clone)
13
- end
14
-
15
- private
16
-
17
- UNSUPPORTED_SWITCHES = %w[--host --port --https --root -r --config -c]
18
- private_constant :UNSUPPORTED_SWITCHES
19
-
20
- # Internal: Allows to prevent configuration mistakes by ensuring the Rails app
21
- # and vite-plugin-ruby are using the same configuration for the dev server.
22
- def detect_unsupported_switches!(args)
23
- return unless (unsupported = UNSUPPORTED_SWITCHES & args).any?
24
-
25
- $stdout.puts "Please set the following switches in your vite.json instead: #{ unsupported }."
26
- exit!
27
- end
28
-
29
- # Internal: Executes the command with the specified arguments.
30
- def execute_command(args)
31
- cmd = vite_executable
32
- cmd.prepend('node', '--inspect-brk') if args.include?('--debug')
33
- cmd.prepend('node', '--trace-deprecation') if args.delete('--trace-deprecation')
34
- args.append('--mode', ViteRails.mode) unless args.include?('--mode') || args.include?('-m')
35
- cmd += args
36
- Dir.chdir(File.expand_path('.', Dir.pwd)) { Kernel.exec(ViteRails.config.to_env, *cmd) }
37
- end
38
-
39
- # Internal: Resolves to an executable for Vite.
40
- def vite_executable
41
- executable_exists?(path = vite_bin_path) ? [path] : %w[yarn vite]
42
- end
43
-
44
- # Internal: Only so that we can easily cover both paths in tests
45
- def executable_exists?(path)
46
- File.exist?(path)
47
- end
48
-
49
- # Internal: Returns a path where a Vite executable should be found.
50
- def vite_bin_path
51
- ENV["#{ ViteRails::ENV_PREFIX }_VITE_BIN_PATH"] || `yarn bin vite`.chomp.presence || "#{ `npm bin`.chomp }/vite"
52
- end
53
- end
data/package.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "name": "only-for-workflows",
3
- "version": "unknown",
4
- "license": "MIT",
5
- "scripts": {
6
- "docs": "npm -C docs run docs",
7
- "docs:build": "npm -C docs run docs:build",
8
- "docs:search": "npm -C docs run docs:search",
9
- "docs:lint": "npm -C docs run lint",
10
- "build": "rm -rf package/dist && npm -C package run prerelease",
11
- "release": "rm -rf package/dist && npm -C package run release",
12
- "lint": "npm -C package run lint",
13
- "test": "npm -C package run test"
14
- },
15
- "dependencies": {
16
- "vite": "^2.0.0-beta.46",
17
- "vite-plugin-ruby": "^1.0.5"
18
- }
19
- }
@@ -1,16 +0,0 @@
1
- {
2
- "assetHost": null,
3
- "assetsDir": "assets",
4
- "autoBuild": false,
5
- "buildCacheDir": "tmp/cache/vite",
6
- "publicOutputDir": "vite",
7
- "configPath": "config/vite.json",
8
- "publicDir": "public",
9
- "entrypointsDir": "entrypoints",
10
- "sourceCodeDir": "app/frontend",
11
- "host": "localhost",
12
- "https": null,
13
- "port": 3036,
14
- "hideBuildConsoleOutput": false,
15
- "watchAdditionalPaths": []
16
- }
data/test/builder_test.rb DELETED
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class BuilderTest < ViteRails::Test
6
- def setup
7
- refresh_config
8
- ViteRails.builder.send(:files_digest_path).tap do |path|
9
- path.delete if path.exist?
10
- end
11
- end
12
-
13
- def teardown
14
- setup
15
- end
16
-
17
- def vite_env
18
- ViteRails.config.to_env
19
- end
20
-
21
- def test_custom_environment_variables
22
- assert_nil vite_env['FOO']
23
- ViteRails.env['FOO'] = 'BAR'
24
- assert vite_env['FOO'] == 'BAR'
25
- end
26
-
27
- def test_freshness
28
- assert ViteRails.builder.stale?
29
- assert !ViteRails.builder.fresh?
30
- end
31
-
32
- def test_build
33
- assert !ViteRails.builder.build
34
- end
35
-
36
- def test_freshness_on_build_success
37
- assert ViteRails.builder.stale?
38
- status = OpenStruct.new(success?: true)
39
- Open3.stub :capture3, [:sterr, :stdout, status] do
40
- assert ViteRails.builder.build
41
- assert ViteRails.builder.fresh?
42
- end
43
- end
44
-
45
- def test_freshness_on_build_fail
46
- assert ViteRails.builder.stale?
47
- status = OpenStruct.new(success?: false)
48
- Open3.stub :capture3, [:sterr, :stdout, status] do
49
- assert !ViteRails.builder.build
50
- assert ViteRails.builder.fresh?
51
- end
52
- end
53
-
54
- def test_files_digest_path
55
- assert_equal ViteRails.builder.send(:files_digest_path).basename.to_s, "last-compilation-digest-#{ ViteRails.config.mode }"
56
- end
57
-
58
- def test_watched_files_digest
59
- previous_digest = ViteRails.builder.send(:watched_files_digest)
60
- refresh_config
61
- assert_equal previous_digest, ViteRails.builder.send(:watched_files_digest)
62
- end
63
-
64
- def test_external_env_variables
65
- assert_equal 'production', vite_env['VITE_RUBY_MODE']
66
- assert_equal Rails.root.to_s, vite_env['VITE_RUBY_ROOT']
67
-
68
- ENV['VITE_RUBY_MODE'] = 'foo.bar'
69
- ENV['VITE_RUBY_ROOT'] = '/baz'
70
- refresh_config
71
- assert_equal 'foo.bar', vite_env['VITE_RUBY_MODE']
72
- assert_equal '/baz', vite_env['VITE_RUBY_ROOT']
73
- ensure
74
- ENV.delete('VITE_RUBY_MODE')
75
- ENV.delete('VITE_RUBY_ROOT')
76
- end
77
- end