diff --git a/docs/config/index.md b/docs/config/index.md index f8460f82..ac17b172 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -33,7 +33,7 @@ export default defineConfig({ RubyPlugin(), ], optimizeDeps: { - exclude: [/webpack/, /vite-plugin-ruby/], + exclude: [/webpack/], // In case webpacker is installed (these deps won't be imported) }, }) ``` diff --git a/examples/blog/Gemfile b/examples/blog/Gemfile index 21311b07..fc98f028 100644 --- a/examples/blog/Gemfile +++ b/examples/blog/Gemfile @@ -23,7 +23,7 @@ gem 'jbuilder', '~> 2.7' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' -gem 'vite_rails', '1.0.10' # path: '../..' +gem 'vite_rails', path: '../..'#, '1.0.10' # Use Active Storage variant # gem 'image_processing', '~> 1.2' diff --git a/examples/blog/Gemfile.lock b/examples/blog/Gemfile.lock index b79b75f8..9fa7736a 100644 --- a/examples/blog/Gemfile.lock +++ b/examples/blog/Gemfile.lock @@ -1,3 +1,12 @@ +PATH + remote: ../.. + specs: + vite_rails (1.0.10) + activesupport (>= 5.1) + rack-proxy (>= 0.6.1) + railties (>= 5.1) + zeitwerk + GEM remote: https://rubygems.org/ specs: @@ -207,11 +216,6 @@ GEM turbolinks-source (5.2.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) - vite_rails (1.0.10) - activesupport (>= 5.1) - rack-proxy (>= 0.6.1) - railties (>= 5.1) - zeitwerk web-console (4.1.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -252,7 +256,7 @@ DEPENDENCIES spring-watcher-listen (~> 2.0.0) turbolinks (~> 5) tzinfo-data - vite_rails (= 1.0.10) + vite_rails! web-console (>= 3.3.0) webdrivers webpacker (~> 4.0) diff --git a/examples/blog/app/frontend/entrypoints/application.js b/examples/blog/app/frontend/entrypoints/application.js index 605e7507..1333128a 100644 --- a/examples/blog/app/frontend/entrypoints/application.js +++ b/examples/blog/app/frontend/entrypoints/application.js @@ -2,7 +2,7 @@ import '@rails/ujs' import Turbolinks from 'turbolinks' -import ActiveStorage from '@rails/activestorage' +import * as ActiveStorage from '@rails/activestorage' // Import all channels. import.meta.globEager('../channels/**/*_channel.js') diff --git a/examples/blog/config/initializers/assets.rb b/examples/blog/config/initializers/assets.rb index a9b0d0f1..362416f4 100644 --- a/examples/blog/config/initializers/assets.rb +++ b/examples/blog/config/initializers/assets.rb @@ -8,7 +8,7 @@ # Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path # Add Yarn node_modules folder to the asset load path. -Rails.application.config.assets.paths << Rails.root.join('node_modules') +# Rails.application.config.assets.paths << Rails.root.join('node_modules') # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets diff --git a/examples/blog/package.json b/examples/blog/package.json index 651f8db8..b9b02bdf 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -1,19 +1,20 @@ { "name": "blog", "private": true, + "license": "MIT", "dependencies": { "@rails/actioncable": "^6.0.0", "@rails/activestorage": "^6.0.0", "@rails/ujs": "^6.0.0", "@rails/webpacker": "4.3.0", - "tailwindcss": "^2.0.2", - "turbolinks": "^5.2.0", - "vite": "^2.0.0-beta.34", - "vite-plugin-ruby": "^1.0.4" + "turbolinks": "^5.2.0" }, "version": "0.1.0", "devDependencies": { - "webpack-dev-server": "^3.11.2", - "postcss": "8.2.4" + "vite-plugin-ruby": "file:../../package", + "postcss": "8.2.4", + "vite": "^2.0.0-beta.46", + "tailwindcss": "^2.0.2", + "webpack-dev-server": "^3.11.2" } } diff --git a/examples/blog/vite.config.ts b/examples/blog/vite.config.ts index 7fcc3bee..b9832a66 100644 --- a/examples/blog/vite.config.ts +++ b/examples/blog/vite.config.ts @@ -6,6 +6,6 @@ export default defineConfig({ RubyPlugin(), ], optimizeDeps: { - exclude: [/webpack/, /vite-plugin-ruby/], + exclude: [/webpack/], // In case webpacker is installed (these deps won't be imported) }, }) diff --git a/examples/blog/yarn.lock b/examples/blog/yarn.lock index 07bfe4e1..dfe05e93 100644 --- a/examples/blog/yarn.lock +++ b/examples/blog/yarn.lock @@ -2848,10 +2848,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@^0.8.26: - version "0.8.33" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.33.tgz#4e24ab4e780b08ff5527171bf5a684594c8b56e9" - integrity sha512-2ms/P6Y9zJfopR9dKo2vHzhXKfGSNlquVVoVOF8YnhjuzZVrvManMVBPadBsR/t7jzIkRnwqvxrs7d4f3C3eyg== +esbuild@^0.8.34: + version "0.8.34" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.34.tgz#16b4ac58f74c821d2c5a8c2f0585ca96a38ab4e6" + integrity sha512-tnr0V1ooakYr1aRLXQLzCn2GVG1kBTW3FWpRyC+NgrR3ntsouVpJOlTOV0BS4YLATx3/c+x3h/uBq9lWJlUAtQ== escalade@^3.1.1: version "3.1.1" @@ -7647,19 +7647,17 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite-plugin-ruby@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vite-plugin-ruby/-/vite-plugin-ruby-1.0.4.tgz#0f4a263fd79a082a84917a54b0881f02a3bbfa61" - integrity sha512-WJE+c2TGLwcbSHzkqcwCmPcHxasUnXmx5Bi1HPO89Yo+Mggi8t/fO/WIPUF7NxSlp9q2lq5/L3Vnkt3R/tolPg== +"vite-plugin-ruby@file:../../package": + version "1.0.5" dependencies: fast-glob "^3.2.4" -vite@^2.0.0-beta.34: - version "2.0.0-beta.34" - resolved "https://registry.yarnpkg.com/vite/-/vite-2.0.0-beta.34.tgz#8db57443789b1bb0eac624cc596f3aeb7fde9eea" - integrity sha512-D4/2WBf219mZBgDRiKfMwK/07UGiP+d56W2a2SEqf21iMOfM3yNBf3cfTY7qrHoi28EUo8l1LVwkSFPNbFlV2w== +vite@^2.0.0-beta.46: + version "2.0.0-beta.46" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.0.0-beta.46.tgz#9c0d35019c350fbebd17f84c4e7243fffccd1819" + integrity sha512-RiiJdjiFDaM9youfcTFnCztstwBXHHSdsSATZVD5A4QSb39KJRTpSKoveFo0PT7VJM5HjOP7QC/sVOqX011F6Q== dependencies: - esbuild "^0.8.26" + esbuild "^0.8.34" postcss "^8.2.1" resolve "^1.19.0" rollup "^2.35.1" diff --git a/lib/install/config/vite.config.ts b/lib/install/config/vite.config.ts index 7fcc3bee..b9832a66 100644 --- a/lib/install/config/vite.config.ts +++ b/lib/install/config/vite.config.ts @@ -6,6 +6,6 @@ export default defineConfig({ RubyPlugin(), ], optimizeDeps: { - exclude: [/webpack/, /vite-plugin-ruby/], + exclude: [/webpack/], // In case webpacker is installed (these deps won't be imported) }, }) diff --git a/lib/install/template.rb b/lib/install/template.rb index f22c9e06..6fa76c6b 100644 --- a/lib/install/template.rb +++ b/lib/install/template.rb @@ -33,8 +33,8 @@ vite_version = package_json.match(/"vite": "(.*)"/)[1] plugin_version = package_json.match(/"vite-plugin-ruby": "(.*)"/)[1] - say 'Installing vite as direct dependencies' - run "yarn add vite@#{ vite_version } vite-plugin-ruby@#{ plugin_version }" + say 'Installing vite as build dependencies' + run "yarn add -D vite@#{ vite_version } vite-plugin-ruby@#{ plugin_version }" end say 'Vite ⚡️ Rails successfully installed! 🎉', :green diff --git a/lib/tasks/vite/build.rake b/lib/tasks/vite/build.rake index 420da9fa..11197f19 100644 --- a/lib/tasks/vite/build.rake +++ b/lib/tasks/vite/build.rake @@ -3,14 +3,24 @@ $stdout.sync = true def enhance_assets_precompile + # Before installing + ['yarn:install', 'webpacker:yarn_install'].each do |name| + Rake::Task[name].enhance([:'vite:set_node_env']) if Rake::Task.task_defined?(name) + end + + # After precompiling Rake::Task['assets:precompile'].enhance do |task| prefix = task.name.split(/#|assets:precompile/).first - Rake::Task["#{ prefix }vite:build"].invoke end end namespace :vite do + desc 'Fixes Rails management of node dev dependencies (build dependencies)' + task :set_node_env do + ENV['NODE_ENV'] = 'development' + end + desc 'Compile JavaScript packs using vite for production with digests' task build: [:'vite:verify_install', :environment] do ViteRails.build_from_rake diff --git a/lib/tasks/vite/install_dependencies.rake b/lib/tasks/vite/install_dependencies.rake index f117f90d..a4720487 100644 --- a/lib/tasks/vite/install_dependencies.rake +++ b/lib/tasks/vite/install_dependencies.rake @@ -1,19 +1,13 @@ # frozen_string_literal: true namespace :vite do - desc 'Support for older Rails versions. Install all JavaScript dependencies as specified via Yarn' + desc 'Install all JavaScript dependencies as specified via Yarn' task :install_dependencies do valid_node_envs = %w[test development production] node_env = ENV.fetch('NODE_ENV') { valid_node_envs.include?(Rails.env) ? Rails.env : 'production' } Dir.chdir(Rails.root) do - install_command = if Rails.root.join('yarn.lock').exist? - v1 = `yarn --version`.start_with?('1') - "yarn install #{ v1 ? '--no-progress --frozen-lockfile' : '--immutable' }" - elsif Rails.root.join('pnpm-lock.yaml').exist? - 'pnpm install' - else - 'npm ci' - end + v1 = `yarn --version`.start_with?('1') + install_command = "yarn install #{ v1 ? '--no-progress --frozen-lockfile' : '--immutable' } --production=false" system({ 'NODE_ENV' => node_env }, install_command) end end diff --git a/lib/vite_rails.rb b/lib/vite_rails.rb index 71d40f45..acb62e8e 100644 --- a/lib/vite_rails.rb +++ b/lib/vite_rails.rb @@ -14,7 +14,7 @@ class ViteRails ENV_PREFIX = 'VITE_RUBY' class << self - delegate :config, :builder, :manifest, :commands, :dev_server, :dev_server_running?, to: :instance + delegate :config, :builder, :manifest, :commands, :dev_server, :dev_server_running?, :run_proxy?, to: :instance delegate :mode, to: :config delegate :bootstrap, :clean, :clean_from_rake, :clobber, :build, :build_from_rake, to: :commands @@ -29,14 +29,6 @@ def run(args) ViteRails::Runner.new(args).run end - # Public: The proxy for assets should only run in development mode. - def run_proxy? - config.mode == 'development' - rescue StandardError => error - logger.error("Failed to check mode for Vite: #{ error.message }") - false - end - # Internal: Allows to obtain any env variables for configuration options. def load_env_variables ENV.select { |key, _| key.start_with?(ENV_PREFIX) } @@ -53,7 +45,15 @@ def load_env_variables # Public: Returns true if the Vite development server is running. def dev_server_running? - ViteRails.run_proxy? && dev_server.running? + run_proxy? && dev_server.running? + end + + # Public: The proxy for assets should only run in development mode. + def run_proxy? + config.mode == 'development' + rescue StandardError => error + ViteRails.logger.error("Failed to check mode for Vite: #{ error.message }") + false end # Public: Current instance configuration for Vite. diff --git a/lib/vite_rails/config.rb b/lib/vite_rails/config.rb index 7a6ce5d4..dbf1d84b 100644 --- a/lib/vite_rails/config.rb +++ b/lib/vite_rails/config.rb @@ -55,7 +55,7 @@ def to_env def coerce_values(config) config['mode'] = config['mode'].to_s config['port'] = config['port'].to_i - coerce_paths(config, 'root', 'public_output_dir') + config['root'] = Pathname.new(config['root']) config['build_cache_dir'] = config['root'].join(config['build_cache_dir']) coerce_booleans(config, 'auto_build', 'hide_build_console_output', 'https') end @@ -65,14 +65,9 @@ def coerce_booleans(config, *names) names.each { |name| config[name] = [true, 'true'].include?(config[name]) } end - # Internal: Converts configuration options to pathname. - def coerce_paths(config, *names) - names.each { |name| config[name] = Pathname.new(config[name]) unless config[name].nil? } - end - class << self # Public: Returns the project configuration for Vite. - def resolve_config(attrs = {}) + def resolve_config(**attrs) config = attrs.transform_keys(&:to_s).reverse_merge(config_defaults) file_path = File.join(config['root'], config['config_path']) file_config = config_from_file(file_path, mode: config['mode']) diff --git a/lib/vite_rails/helper.rb b/lib/vite_rails/helper.rb index efd4fe64..558f9fde 100644 --- a/lib/vite_rails/helper.rb +++ b/lib/vite_rails/helper.rb @@ -11,7 +11,9 @@ def current_vite_instance # Public: Renders a script tag for vite/client to enable HMR in development. def vite_client_tag - content_tag('script', '', src: '/@vite/client', type: 'module') if ViteRails.dev_server_running? + return unless current_vite_instance.dev_server_running? + + content_tag('script', '', src: current_vite_instance.manifest.prefix_vite_asset('@vite/client'), type: 'module') end # Public: Resolves the path for the specified Vite asset. @@ -33,12 +35,12 @@ def vite_javascript_tag(*names, js_entries = names.map { |name| current_vite_instance.manifest.lookup!(name, type: asset_type) } js_tags = javascript_include_tag(*js_entries.map { |entry| entry['file'] }, crossorigin: crossorigin, type: type, **options) - unless skip_preload_tags || ViteRails.dev_server_running? + unless skip_preload_tags || current_vite_instance.dev_server_running? preload_paths = js_entries.flat_map { |entry| entry['imports'] }.compact.uniq preload_tags = preload_paths.map { |path| preload_link_tag(path, crossorigin: crossorigin) } end - unless skip_style_tags || ViteRails.dev_server_running? + unless skip_style_tags || current_vite_instance.dev_server_running? style_paths = names.map { |name| current_vite_instance.manifest.lookup(name.delete_suffix('.js'), type: :stylesheet)&.fetch('file') }.compact diff --git a/lib/vite_rails/manifest.rb b/lib/vite_rails/manifest.rb index 68d97bdb..1bb41dc3 100644 --- a/lib/vite_rails/manifest.rb +++ b/lib/vite_rails/manifest.rb @@ -42,6 +42,11 @@ def refresh @manifest = load_manifest end + # Public: Scopes an asset to the output folder in public, as a path. + def prefix_vite_asset(path) + File.join("/#{ config.public_output_dir }", path) + end + private delegate :config, :builder, :dev_server_running?, to: :@vite_rails @@ -55,7 +60,7 @@ def should_build? # Internal: Finds the specified entry in the manifest. def find_manifest_entry(name) if dev_server_running? - { 'file' => "/#{ config.public_output_dir.join(name.to_s) }" } + { 'file' => prefix_vite_asset(name.to_s) } else manifest[name.to_s] end @@ -80,8 +85,8 @@ def manifest def load_manifest if config.manifest_path.exist? JSON.parse(config.manifest_path.read).each do |_, entry| - entry['file'] = within_public_output_dir(entry['file']) - entry['imports'] = entry['imports']&.map { |path| within_public_output_dir(path) } + entry['file'] = prefix_vite_asset(entry['file']) + entry['imports'] = entry['imports']&.map { |path| prefix_vite_asset(path) } end else {} @@ -96,11 +101,6 @@ def with_file_extension(name, entry_type) extension ? "#{ name }.#{ extension }" : name end - # Internal: Scopes the paths in the manifest to the output folder in public. - def within_public_output_dir(path) - "/#{ config.public_output_dir.join(path) }" - end - # Internal: Allows to receive :javascript and :stylesheet as :type in helpers. def extension_for_type(entry_type) case entry_type diff --git a/package.json b/package.json index 928d244b..9b1baee9 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,12 @@ "docs:build": "npm -C docs run docs:build", "docs:search": "npm -C docs run docs:search", "docs:lint": "npm -C docs run lint", + "build": "rm -rf package/dist && npm -C package run prerelease", "lint": "npm -C package run lint", "test": "npm -C package run test" }, "dependencies": { - "vite": "^2.0.0-beta.34", + "vite": "^2.0.0-beta.46", "vite-plugin-ruby": "^1.0.4" } } diff --git a/package/README.md b/package/README.md index a4f582bd..e55a8b6b 100644 --- a/package/README.md +++ b/package/README.md @@ -39,9 +39,6 @@ export default { Vue(), ViteRuby(), ], - optimizeDeps: { - exclude: [/vite-plugin-ruby/], - }, }; ``` diff --git a/package/example/app/frontend/components/HelloWorld.vue b/package/example/app/frontend/components/HelloWorld.vue index f5e9769a..4da6778f 100644 --- a/package/example/app/frontend/components/HelloWorld.vue +++ b/package/example/app/frontend/components/HelloWorld.vue @@ -53,4 +53,4 @@ a {
Edit components/HelloWorld.vue
to test hot module replacement.