Skip to content

Commit

Permalink
TypeScript support for the installation generator
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed Aug 6, 2024
1 parent e4bb474 commit 1d2756a
Show file tree
Hide file tree
Showing 19 changed files with 618 additions and 10 deletions.
40 changes: 36 additions & 4 deletions lib/generators/inertia/install/frameworks.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
react:
packages:
- "@inertiajs/react"
- "@vitejs/plugin-react"
- "react"
- "react-dom"
- "@vitejs/plugin-react"
packages_ts:
- "@types/react"
- "@types/react-dom"
- "typescript"
vite_plugin_import: "import react from '@vitejs/plugin-react'"
vite_plugin_call: "react()"
copy_files:
copy_files_ts:
"InertiaExample.tsx": "%{js_destination_path}/pages/InertiaExample.tsx"
"tsconfig.json": "tsconfig.json"
"tsconfig.app.json": "tsconfig.app.json"
"tsconfig.node.json": "tsconfig.node.json"
"vite-env.d.ts": "%{js_destination_path}/vite-env.d.ts"
copy_files_js:
"InertiaExample.jsx": "%{js_destination_path}/pages/InertiaExample.jsx"
copy_files:
"InertiaExample.module.css": "%{js_destination_path}/pages/InertiaExample.module.css"
"../assets/react.svg": "%{js_destination_path}/assets/react.svg"
"../assets/inertia.svg": "%{js_destination_path}/assets/inertia.svg"
Expand All @@ -18,24 +29,45 @@ vue:
- "@inertiajs/vue3"
- "vue"
- "@vitejs/plugin-vue"
packages_ts:
- "typescript"
- "vue-tsc"
vite_plugin_import: "import vue from '@vitejs/plugin-vue'"
vite_plugin_call: "vue()"
copy_files:
"InertiaExample.vue": "%{js_destination_path}/pages/InertiaExample.vue"
"../assets/vue.svg": "%{js_destination_path}/assets/vue.svg"
"../assets/inertia.svg": "%{js_destination_path}/assets/inertia.svg"
"../assets/vite_ruby.svg": "%{js_destination_path}/assets/vite_ruby.svg"
copy_files_ts:
"InertiaExample.ts.vue": "%{js_destination_path}/pages/InertiaExample.vue"
"tsconfig.json": "tsconfig.json"
"tsconfig.app.json": "tsconfig.app.json"
"tsconfig.node.json": "tsconfig.node.json"
"vite-env.d.ts": "%{js_destination_path}/vite-env.d.ts"
copy_files_js:
"InertiaExample.vue": "%{js_destination_path}/pages/InertiaExample.vue"

svelte:
packages:
- "@inertiajs/svelte"
- "svelte"
- "@sveltejs/vite-plugin-svelte"
packages_ts:
- "@tsconfig/svelte"
- "svelte-check"
- "typescript"
- "tslib"
vite_plugin_import: "import { svelte } from '@sveltejs/vite-plugin-svelte'"
vite_plugin_call: "svelte()"
copy_files_ts:
"InertiaExample.ts.svelte": "%{js_destination_path}/pages/InertiaExample.svelte"
"tsconfig.json": "tsconfig.json"
"tsconfig.node.json": "tsconfig.node.json"
"vite-env.d.ts": "%{js_destination_path}/vite-env.d.ts"
copy_files_js:
"InertiaExample.svelte": "%{js_destination_path}/pages/InertiaExample.svelte"
copy_files:
"svelte.config.js": "svelte.config.js"
"InertiaExample.svelte": "%{js_destination_path}/pages/InertiaExample.svelte"
"../assets/svelte.svg": "%{js_destination_path}/assets/svelte.svg"
"../assets/inertia.svg": "%{js_destination_path}/assets/inertia.svg"
"../assets/vite_ruby.svg": "%{js_destination_path}/assets/vite_ruby.svg"
50 changes: 44 additions & 6 deletions lib/generators/inertia/install/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class InstallGenerator < Rails::Generators::Base
enum: FRAMEWORKS.keys,
default: nil

class_option :typescript, type: :boolean, default: false,
desc: "Whether to use TypeScript"

class_option :package_manager, type: :string, default: nil, enum: %w[npm yarn bun],
desc: "The package manager you want to use to install Inertia's npm packages"

Expand Down Expand Up @@ -56,6 +59,8 @@ def install
end
end

install_typescript if typescript?

install_tailwind if install_tailwind?

install_inertia
Expand Down Expand Up @@ -84,13 +89,13 @@ def install_inertia
prepend_file vite_config_path, "#{FRAMEWORKS[framework]["vite_plugin_import"]}\n"
end

say "Copying inertia.js entrypoint"
template "#{framework}/inertia.js", js_file_path("entrypoints/inertia.js")
say "Copying #{inertia_entrypoint} entrypoint"
template "#{framework}/#{inertia_entrypoint}", js_file_path("entrypoints/#{inertia_entrypoint}")

if application_layout.exist?
say "Adding inertia.js script tag to the application layout"
say "Adding #{inertia_entrypoint} script tag to the application layout"
headers = <<-ERB
<%= vite_javascript_tag "inertia" %>
<%= #{vite_tag} "inertia" %>
<%= inertia_headers %>
ERB
headers += "\n <%= vite_stylesheet_tag \"application\" %>" if install_tailwind?
Expand All @@ -108,8 +113,22 @@ def install_inertia
say_error "+ <title inertia>...</title>"
say_error "+ <%= inertia_headers %>"
say_error "+ <%= vite_react_refresh_tag %>" if framework == "react"
say_error "+ <%= vite_javascript_tag \"inertia\" %>"
say_error "+ <%= #{vite_tag} \"inertia\" %>"
end
end

def install_typescript
say "Adding TypeScript support"
if framework == "svelte" && inertia_svelte_version <= Gem::Version.new("1.2.0")
say "WARNING: @inertiajs/svelte does not support TypeScript yet.", :yellow
if yes? "Alias @inertiajs/svelte to @westacks/inertia-svelte to enable TypeScript support?", :red
add_packages("@inertiajs/svelte@npm:@westacks/inertia-svelte")
else
say "Skipping TypeScript support for @inertiajs/svelte", :yellow
@typescript = false
end
end
add_packages(*FRAMEWORKS[framework]["packages_ts"])
end

def install_example_page
Expand All @@ -120,7 +139,8 @@ def install_example_page
route "get 'inertia-example', to: 'inertia_example#index'"

say "Copying page assets"
FRAMEWORKS[framework]["copy_files"].each do |source, destination|
copy_files = FRAMEWORKS[framework]["copy_files"].merge(FRAMEWORKS[framework]["copy_files_#{typescript? ? "ts" : "js"}"])
copy_files.each do |source, destination|
template "#{framework}/#{source}", file_path(destination % {js_destination_path: js_destination_path})
end
end
Expand Down Expand Up @@ -188,6 +208,24 @@ def install_tailwind?
@install_tailwind = options[:install_tailwind] || yes?("Would you like to install Tailwind CSS? (y/n)", :green)
end

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

@typescript = options[:typescript] || yes?("Would you like to use TypeScript? (y/n)", :green)
end

def inertia_entrypoint
"inertia.#{typescript? ? "ts" : "js"}"
end

def vite_tag
typescript? ? "vite_typescript_tag" : "vite_javascript_tag"
end

def inertia_svelte_version
@inertia_svelte_version ||= Gem::Version.new(`npm show @inertiajs/svelte version`.strip)
end

def framework
@framework ||= options[:framework] || ask("What framework do you want to use with Inertia?", :green, limited_to: FRAMEWORKS.keys, default: "react")
end
Expand Down
60 changes: 60 additions & 0 deletions lib/generators/inertia/install/templates/react/InertiaExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Head } from '@inertiajs/react'
import { useState } from 'react'

import reactSvg from '/assets/react.svg'
import inertiaSvg from '/assets/inertia.svg'
import viteRubySvg from '/assets/vite_ruby.svg'

import cs from './InertiaExample.module.css'

export default function InertiaExample({ name }: { name: string }) {
const [count, setCount] = useState(0)

return (
<>
<Head title="Inertia + Vite Ruby + React Example" />

<div className={cs.root}>
<h1 className={cs.h1}>Hello {name}!</h1>

<div>
<a href="https://inertia-rails.netlify.app" target="_blank">
<img className={cs.logo} src={inertiaSvg} alt="Inertia logo" />
</a>
<a href="https://vite-ruby.netlify.app" target="_blank">
<img
className={`${cs.logo} ${cs.vite}`}
src={viteRubySvg}
alt="Vite Ruby logo"
/>
</a>
<a href="https://react.dev" target="_blank">
<img
className={`${cs.logo} ${cs.react}`}
src={reactSvg}
alt="React logo"
/>
</a>
</div>

<h2 className={cs.h2}>Inertia + Vite Ruby + React</h2>

<div className="card">
<button
className={cs.button}
onClick={() => setCount((count) => count + 1)}
>
count is {count}
</button>
<p>
Edit <code>app/frontend/pages/InertiaExample.jsx</code> and save to
test HMR
</p>
</div>
<p className={cs.readTheDocs}>
Click on the Inertia, Vite Ruby, and React logos to learn more
</p>
</div>
</>
)
}
34 changes: 34 additions & 0 deletions lib/generators/inertia/install/templates/react/inertia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createInertiaApp } from '@inertiajs/react'
import { createElement } from 'react'
import { createRoot } from 'react-dom/client'

createInertiaApp({
// Set default page title
// see https://inertia-rails.netlify.app/guide/title-and-meta
//
// title: title => title ? `${title} - App` : 'App',

// Disable progress bar
//
// see https://inertia-rails.netlify.app/guide/progress-indicators
// progress: false,

resolve: (name) => {
const pages = import.meta.glob('../pages/**/*.tsx', { eager: true })
return pages[`../pages/${name}.tsx`]

// To use a default layout, import the Layout component
// and use the following lines.
// see https://inertia-rails.netlify.app/guide/pages#default-layouts
//
// const page = pages[`../pages/${name}.tsx`]
// page.default.layout ||= (page) => createElement(Layout, null, page)
// return page
},

setup({ el, App, props }) {
const root = createRoot(el)

root.render(createElement(App, props))
},
})
27 changes: 27 additions & 0 deletions lib/generators/inertia/install/templates/react/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
},
"include": ["<%= js_destination_path %>"]
}
11 changes: 11 additions & 0 deletions lib/generators/inertia/install/templates/react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
]
}
13 changes: 13 additions & 0 deletions lib/generators/inertia/install/templates/react/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true,
"noEmit": true
},
"include": ["vite.config.ts"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading

0 comments on commit 1d2756a

Please sign in to comment.