Skip to content

Commit

Permalink
Add install generator
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed May 31, 2024
1 parent a872c63 commit a8afe2d
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 1 deletion.
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,43 @@

## Installation

To install `TurboMount`, add the following line to your Gemfile:
To install Turbo Mount, add the following line to your `Gemfile` and run `bundle install`:

```ruby
gem "turbo-mount"
```

### Automatic Installation

Run the following command to install the necessary files:

```bash
bin/rails generate turbo_mount:install
```

This will add `turbo-mount` package and framework dependencies to your `package.json` or `importmap.rb`, and create the Turbo Mount initialization file.

### Manual Installation

You can also install the necessary JavaScript files manually.

If your project utilizes build tools such as [Vite](http://vite-ruby.netlify.app), also install the `turbo-mount` package:

```bash
npm install turbo-mount
# or with yarn
yarn add turbo-mount

# and the desired framework
npm install react react-dom
# or
npm install vue
# or
npm install svelte
```

If you're using Vite, don't forget to add [framework-specific plugins](https://vitejs.dev/plugins) to your `vite.config.js`.

### Importmaps
To use `TurboMount` with importmaps, you need to pin the necessary JavaScript files in your `config/importmap.rb`:

Expand All @@ -49,6 +72,18 @@ pin "turbo-mount/react", to: "turbo-mount/react.min.js"

This ensures that `turbo-mount` and its plugins are available in your application.

Also pin the desired framework:

```bash
bin/importmap pin react react-dom react-dom/client
# or
bin/importmap pin vue
# or
bin/importmap pin svelte
```

Note: Importmap-only mode is quite limited in terms of JavaScript dependencies. If you're using a more complex setup, consider using a bundler like Vite.

## Usage

### Initialization
Expand Down
16 changes: 16 additions & 0 deletions lib/generators/turbo_mount/install/turbo-mount.js.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TurboMount<%= framework.capitalize %> } from "turbo-mount/<%= framework %>";

const turboMount = new TurboMount<%= framework.capitalize %>();

// to register a component use:
// turboMount.register("Hello", Hello); // where Hello is the imported the component

// to override the default controller use:
// turboMount.register("Hello", Hello, HelloController); // where HelloController is a Stimulus controller extended from TurboMount<%= framework.capitalize %>Controller
<%- if vite? -%>

// If you want to automatically register components use:
// const controllers = import.meta.glob("/controllers/**/*_controller.js", { eager: true });
// const components = import.meta.glob("/components/**/*.jsx", { eager: true });
// registerComponents({ turboMount, components, controllers });
<%- end -%>
112 changes: 112 additions & 0 deletions lib/generators/turbo_mount/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# frozen_string_literal: true

module TurboMount
module Generators
class InstallGenerator < Rails::Generators::Base
FRAMEWORKS = {
"react" => {
pins: "react react-dom react-dom/client",
npm_packages: "react react-dom",
vite_plugin: "@vitejs/plugin-react"
},
"vue" => {
pins: "vue",
npm_packages: "vue",
vite_plugin: "@vitejs/plugin-vue"
},
"svelte" => {
pins: "svelte",
npm_packages: "svelte",
vite_plugin: "@sveltejs/vite-plugin-svelte"
}
}.freeze

source_root File.expand_path("install", __dir__)

def install
say "Installing Turbo Mount"

if build_tool.nil?
say "Could not find a package.json or config/importmap.rb file to add the turbo-mount dependency to, please add it manually.", :red
exit!
end

if importmap?
install_importmap
else
install_nodejs
end

say "Turbo Mount successfully installed", :green
end

private

def install_nodejs
case build_tool
when "npm"
run "npm install turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
when "yarn"
run "yarn add turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
when "bun"
run "bun add turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
end

say "Creating Turbo Mount initializer"
template "turbo-mount.js", File.join("app/javascript/turbo-mount.js")
append_to_file "app/javascript/entrypoints/application.js", %(import "./turbo-mount"\n)
warn_about_vite_plugin if vite?
end

def install_importmap
say "Creating Turbo Mount initializer"
template "turbo-mount.js", File.join("app/javascript/turbo-mount-initializer.js")
append_to_file "app/javascript/application.js", %(import "turbo-mount-initializer"\n)

say "Pinning Turbo Mount to the importmap"
append_to_file "config/importmap.rb", %(pin "turbo-mount", to: "turbo-mount.min.js"\n)
append_to_file "config/importmap.rb", %(pin "turbo-mount-initializer"\n)
append_to_file "config/importmap.rb", %(pin "turbo-mount/#{framework}", to: "turbo-mount/#{framework}.min.js"\n)

say "Pinning framework dependencies to the importmap"
run "bin/importmap pin #{FRAMEWORKS[framework][:pins]}"
end

def vite?
Dir.glob(Rails.root.join("vite.config.*")).any?
end

def importmap?
build_tool == "importmap"
end

def warn_about_vite_plugin
say "Make sure to install and add #{FRAMEWORKS[framework][:vite_plugin]} to your Vite config", :yellow
end

def build_tool
return @build_tool if defined?(@build_tool)

@build_tool = detect_build_tool
end

def detect_build_tool
if Rails.root.join("package.json").exist?
if Rails.root.join("package-lock.json").exist?
"npm"
elsif Rails.root.join("bun.config.js").exist?
"bun"
else
"yarn"
end
elsif Rails.root.join("config/importmap.rb").exist?
"importmap"
end
end

def framework
@framework ||= ask("What framework do you want to use with Turbo Mount?", limited_to: FRAMEWORKS.keys, default: "react")
end
end
end
end

0 comments on commit a8afe2d

Please sign in to comment.