IntelliJ IDEA を 2021.1.2 → 2021.1.3 へ、Git for Windows を 2.31.0 → 2.32.0.2 へバージョンアップ
IntelliJ IDEA を 2021.1.2 → 2021.1.3 へバージョンアップする
IntelliJ IDEA の 2021.1.3 がリリースされているのでバージョンアップします。
- IntelliJ IDEA 2021.1.3 Is Available
https://blog.jetbrains.com/idea/2021/06/intellij-idea-2021-1-3/
※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。
IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。
「IntelliJ IDEA and Plugin Updates」ダイアログが表示されます。右下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。
Plugin の update も表示されました。このまま「Update and Restart」ボタンをクリックします。
Patch がダウンロードされて IntelliJ IDEA が再起動します。
IntelliJ IDEA が起動すると画面下部に「Indexing」のメッセージが表示されますので、終了するまで待機します。
IntelliJ IDEA のメインメニューから「Help」-「About」を選択し、2021.1.3 へバージョンアップされていることを確認します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。
Project Tool Window で src/test でコンテキストメニューを表示して「More Run/Debug」-「Run 'All Tests' with Coverage」を選択し、テストが全て成功することを確認します。
Git for Windows を 2.31.0 → 2.32.0.2 へバージョンアップする
Git for Windows の 2.32.0.2 がリリースされていたのでバージョンアップします。
https://gitforwindows.org/ の「Download」ボタンをクリックして Git-2.32.0.2-64-bit.exe をダウンロードします。
Git-2.32.0.2-64-bit.exe を実行します。
「Git 2.32.0.2 Setup」ダイアログが表示されます。インストーラーの画面を一通り見たいので「Only show new options」のチェックを外してから [Next >] ボタンをクリックします。
「Select Components」画面が表示されます。「Git LFS(Large File Support)」だけチェックした状態で [Next >]ボタンをクリックします。
「Choosing the default editor used by Git」画面が表示されます。「Use Vim (the ubiquitous text editor) as Git's default editor」が選択された状態で [Next >]ボタンをクリックします。
「Adjusting the name of the initial branch in new repositories」画面が表示されます。「Let Git decide」が選択されていることを確認後、[Next >]ボタンをクリックします。
「Adjusting your PATH environment」画面が表示されます。中央の「Git from the command line and also from 3rd-party software」が選択されていることを確認後、[Next >]ボタンをクリックします。
「Choosing HTTPS transport backend」画面が表示されます。「Use the OpenSSL library」が選択されていることを確認後、[Next >]ボタンをクリックします。
「Configuring the line ending conversions」画面が表示されます。一番上の「Checkout Windows-style, commit Unix-style line endings」が選択されていることを確認した後、[Next >]ボタンをクリックします。
「Configuring the terminal emulator to use with Git Bash」画面が表示されます。「Use Windows'default console window」が選択されていることを確認した後、[Next >]ボタンをクリックします。
「Choose the default behavior of
git pull
」画面が表示されます。「Default (fast-forward or merge)」が選択されていることを確認した後、[Next >]ボタンをクリックします。「Choose a credential helper」画面が表示されます。「None」が選択されていることを確認した後、[Next >]ボタンをクリックします。
「Configuring extra options」画面が表示されます。「Enable file system caching」だけがチェックされていることを確認した後、[Next >]ボタンをクリックします。
「Configuring experimental options」画面が表示されます。何もチェックせずに [Install]ボタンをクリックします。
インストールが完了すると「Completing the Git Setup Wizard」のメッセージが表示された画面が表示されます。中央の「View Release Notes」のチェックを外した後、[Next >]ボタンをクリックしてインストーラーを終了します。
コマンドプロンプトを起動して
git --version
を実行し、git のバージョンがgit version 2.32.0.windows.2
になっていることを確認します。特に問題はないようですので、2.32.0.2 で作業を進めたいと思います。
AdoptOpenJDK を 11.0.10+9 → 11.0.11+9 へ、IntelliJ IDEA を 2020.3.3 → 2020.3.4 → 2021.1.2 へバージョンアップ
AdoptOpenJDK を 11.0.10.1+1 → 11.0.11+9 へバージョンアップする
※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。
https://adoptopenjdk.net/ を見ると 11.0.11+9 がダウンロードできるようになっていましたので、11.0.11+9 へバージョンアップします。
インストール時に削除されるかもしれないので D:\Java\jdk-11.0.10.9-hotspot → D:\Java\jdk-11.0.10.9-hotspotx にリネームします。
OpenJDK11U-jdk_x64_windows_hotspot_11.0.11_9.msi をダウンロードして D:\Java\jdk-11.0.11.9-hotspot へインストールした後、環境変数 JAVA_HOME のパスを D:\Java\jdk-11.0.10.9-hotspot へ変更します。
コマンドプロンプトから
java -version
を実行し、11.0.11
に変更されていることを確認します。D:\Java\jdk-11.0.10.9-hotspotx → D:\Java\jdk-11.0.10.9-hotspot に戻します。
IntelliJ IDEA を再起動します。
「Welcome to IntelliJ IDEA」ダイアログで ksbysample-webapp-lending プロジェクトを開いて、プロジェクトが使用する JDK を 11.0.11+9 に変更します。
IntelliJ IDEA のメイン画面が開いたら、メニューから「File」-「Project Structure...」を選択します。
「Project Structure」ダイアログが表示されます。「Project SDK」で D:\Java\jdk-11.0.11.9-hotspot を選択します。
「Project SDK」の「Edit」ボタンをクリックします。
「Project Structure」ダイアログが表示されます。画面左側で「Platform Settings」-「SDKs」を選択して、中央のリストから「11.0.10.9」を選択した後、リストの上の「-」ボタンをクリックして削除します。
中央のリストから「11」を選択した後、"11" → "11.0.11.9" へ変更します。
「OK」ボタンをクリックして「Project Structure for New Projects」ダイアログを閉じます。
メイン画面に戻ると画面右下に「Indexing...」の表示が出るので、終了するまで待ちます。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。
Project Tool Window で src/test でコンテキストメニューを表示して「More Run/Debug」-「Run 'All Tests' with Coverage」を選択し、テストが全て成功することを確認します。
特に問題は発生しませんでした。11.0.11+9 で開発を進めます。
IntelliJ IDEA を 2020.3.3 → 2020.3.4 → 2021.1.2 へバージョンアップする
IntelliJ IDEA の 2021.1.2 がリリースされているのでバージョンアップします。2021.1.2 へのバージョンアップ前に 2020.3.3 → 2020.3.4 へのバージョンアップも実行していますが、今回この手順は書きません。
- IntelliJ IDEA 2021.1 is Out!
https://blog.jetbrains.com/idea/2021/04/intellij-idea-2021-1/ - What’s New in IntelliJ IDEA 2021.1
https://www.jetbrains.com/idea/whatsnew/
※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。
IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。
「IDE and Plugin Updates」ダイアログが表示されます。右下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。
Plugin の update も表示されました。このまま「Update and Restart」ボタンをクリックします。
Patch がダウンロードされて IntelliJ IDEA が再起動します。
IntelliJ IDEA が起動すると画面下部に「Indexing」のメッセージが表示されますので、終了するまで待機します。
IntelliJ IDEA のメインメニューから「Help」-「About」を選択し、2021.1.2 へバージョンアップされていることを確認します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。
Project Tool Window で src/test でコンテキストメニューを表示して「More Run/Debug」-「Run 'All Tests' with Coverage」を選択し、テストが全て成功することを確認します。
Gradle multi-project 内に React アプリ(frontend-app)と Spring Boot アプリ(backend-app)を作成する
概要
記事一覧はこちらです。
Gradle multi-project 内に React+Typescript+Tailwind CSS+React Query 構成の frontend 用アプリと、Sping Boot+springdoc-openapi 構成の REST API を提供する backend 用アプリを作成し、以下の内容を実現します。
- Spring Boot の REST API には @CrossOrigin を付与しません。
- 開発中も本番も frontend から backend の REST API を呼び出す時の URL はパス名のみの
/user/1
にします(http://localhost:8080/user/1
のようにホスト名等は記述しません)。 - 開発中は CRACO で
yarn start
で起動する webpack-dev-server に proxy を設定して、webpack-dev-server 経由で backend 用アプリの REST API にアクセスします。 ※Configuring the Proxy Manually に記述されている src/setupProxy.js を作成・設定する方法もありますが、Tailwind CSS を使う時に CRACO を入れているので今回は CRACO を使う方法を採用しています。 - build タスク実行時に
yarn build
コマンドを実行 → React アプリのファイルを Spring Boot アプリへコピーしてから、Spring Boot アプリの jar ファイルを生成します。
今回作成したソースは ksbysample-react-springboot に置いています。
参照したサイト・書籍
React Query
https://react-query.tanstack.com/CRACO - Configuration
https://github.com/gsoft-inc/craco/blob/master/packages/craco/README.mdwebpack - DevServer - devServer.proxy
https://webpack.js.org/configuration/dev-server/#devserverproxyCreate React App - Proxying API Requests in Development
https://create-react-app.dev/docs/proxying-api-requests-in-development/node-gradle / gradle-node-plugin - Usage
https://github.com/node-gradle/gradle-node-plugin/blob/master/docs/usage.md
目次
- ksbysample-react-springboot レポジトリを作成して clone する
- Spring Initializr でサンプルプロジェクトを作成して Gradle Wrapper のファイルをコピーする
gradlew init
を実行し、build.gradle があるサブプロジェクトを自動認識するよう settings.gradle を変更する- backend-app サブプロジェクトを作成し、REST API を実装する
npx create-react-app frontend-app --template typescript
を実行して frontend-app サブプロジェクトを作成する- Tailwind CSS、CRACO をインストールする
- React Query をインストールする
- frontend-app に REST API を呼び出して取得したデータを表示する処理を実装する
- craco.config.js を変更し webpack-dev-server に proxy の設定を追加する
- Spring Boot アプリを IDEA から起動、React アプリを
yarn start
で起動して動作確認する - frontend-app サブプロジェクトで Gradle の build タスクが実行されるようにし、かつ build タスク実行時に
yarn build
コマンドが実行されるように設定する - backend-app サブプロジェクトで build タスク実行時に frontend-app の build 下のファイルを backend-app/src/main/resources/static にコピーされるように設定する
- プロジェクトのルートディレクトリで Gradle の build タスクを実行する
- 生成された jar ファイルで Spring Boot アプリを起動して動作確認する
手順
ksbysample-react-springboot レポジトリを作成して clone する
ksbysample-react-springboot レポジトリ を作成し、D:\project-react\ksbysample-react-springboot に clone します。
Spring Initializr でサンプルプロジェクトを作成して Gradle Wrapper のファイルをコピーする
適当なディレクトリに Spring Initializr で Spring Boot のプロジェクトを作成し(Gradle を指定する)、Gradle Wrapper の以下のファイルを D:\project-react\ksbysample-react-springboot の下にコピーします。
- gradle ディレクトリ
- gradlew
- gradlew.bat
gradlew init
を実行し、build.gradle があるサブプロジェクトを自動認識するよう settings.gradle を変更する
gradlew init
を実行します。
build.gradle があるサブプロジェクトを自動的に認識してくれるよう settings.gradle を以下の内容に変更します。
rootProject.name = 'ksbysample-react-springboot' rootDir.eachFileRecurse { f -> if (f.name == "build.gradle") { String relativePath = f.parentFile.absolutePath - rootDir.absolutePath String projectName = relativePath.replaceAll("[\\\\\\/]", ":") if (projectName != ":buildSrc") { include projectName } } }
IntelliJ IDEA で D:\project-react\ksbysample-react-springboot を開きます。
backend-app サブプロジェクトを作成し、REST API を実装する
Spring Initializr で D:\project-react\ksbysample-react-springboot の下に backend-app サブプロジェクトを作成します。
D:\project-react\ksbysample-react-springboot\backend-app の下は src ディレクトリ、build.gradle 以外のディレクトリ、ファイルを削除します。
build.gradle を以下の内容に変更します。
plugins { id 'org.springframework.boot' version '2.4.5' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'ksbysample' version = '0.0.1-SNAPSHOT' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 [compileJava, compileTestJava]*.options*.encoding = "UTF-8" [compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"] configurations { compileOnly.extendsFrom annotationProcessor // annotationProcessor と testAnnotationProcessor、compileOnly と testCompileOnly を併記不要にする testAnnotationProcessor.extendsFrom annotationProcessor testImplementation.extendsFrom compileOnly } repositories { mavenCentral() } dependencies { def lombokVersion = "1.18.20" implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' developmentOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' // for lombok // testAnnotationProcessor、testCompileOnly を併記しなくてよいよう configurations で設定している annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") } test { useJUnitPlatform() }
backend-app/src/main/java/ksbysample/backendapp/User.java を作成し、以下の内容を記述します。
package ksbysample.backendapp; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @Builder public class User { private String name; private int age; }
backend-app/src/main/java/ksbysample/backendapp/UserApiController.java を作成し、以下の内容を記述します。
package ksbysample.backendapp; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserApiController { @GetMapping("/{id}") public User findById(@PathVariable String id) { return User.builder() .name(String.format("Tanaka Taro No.%s", id)) .age(25) .build(); } }
npx create-react-app frontend-app --template typescript
を実行して frontend-app サブプロジェクトを作成する
D:\project-react\ksbysample-react-springboot で npx create-react-app frontend-app --template typescript
コマンドを実行し、frontend-app サブプロジェクトを作成します。
cd /d/project-react/ksbysample-react-springboot/frontend-app
した後 yarn start
コマンドを実行し、画面が表示されることを確認します。
Tailwind CSS、CRACO をインストールする
以下のコマンドを実行し Tailwind CSS、CRACO をインストールします(React アプリと Spring Boot アプリを連携するのに Tailwind CSS は必須ではありません)。
yarn add tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat
yarn add -D postcss@^7 autoprefixer@^9
yarn add @tailwindcss/forms
yarn add -D @craco/craco
package.json 内の scripts で react-scripts
→ craco
に変更します。
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" },
プロジェクトのルートディレクトリ直下に craco.config.js を作成し、以下の内容を記述します。
module.exports = { style: { postcss: { plugins: [ require('tailwindcss'), require('autoprefixer'), ], }, }, }
npx tailwindcss init -p
を実行して tailwind.config.js、postcss.config.js を作成した後、tailwind.config.js を以下の内容に変更します。
module.exports = { purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [ require('@tailwindcss/forms'), ], }
frontend-app/src/index.css を以下の内容に変更します。
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind forms;
ここに書いた内容については React+Tailwind CSS+Storybook のプロジェクトを作成する 参照。
React Query をインストールする
React アプリから Spring Boot アプリの REST API を呼び出すのに React Query を使用します。yarn add react-query
コマンドを実行してインストールします。
frontend-app に REST API を呼び出して取得したデータを表示する処理を実装する
frontend-app/src/index.tsx を以下のように変更します。
import React from 'react'; import ReactDOM from 'react-dom'; import { QueryClient, QueryClientProvider } from 'react-query'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; const queryClient = new QueryClient(); ReactDOM.render( <React.StrictMode> <QueryClientProvider client={queryClient}> <App /> </QueryClientProvider> </React.StrictMode>, document.getElementById('root') ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
- 以下の行を追加します。
import { QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
<App />
の前後に<QueryClientProvider client={queryClient}> ... </QueryClientProvider>
を追加します。
frontend-app/src/App.tsx を以下の内容に変更します。REST API を呼び出す時の URL は /user/1
固定です。
import { FC } from 'react'; import { useQuery } from 'react-query'; type User = { name: string; age: number; }; const getUser = async () => (await fetch('/user/1')).json(); const App: FC = () => { const { data: user } = useQuery<User>(['user', 1], () => getUser()); return ( <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold"> {user?.name} は {user?.age} 歳です。 </div> ); }; export default App;
craco.config.js を変更し webpack-dev-server に proxy の設定を追加する
frontend-app/craco.config.js に devServer: { ... }
を追加して、/user/...
でアクセスされたら Spring Boot アプリに転送するようにします。
module.exports = { style: { postcss: { plugins: [require('tailwindcss'), require('autoprefixer')], }, }, devServer: { proxy: [ { context: ['/user'], target: 'http://localhost:8080', changeOrigin: true, }, ], }, };
Spring Boot アプリを IDEA から起動、React アプリを yarn start
で起動して動作確認する
Spring Boot アプリを IDEA から起動します。
React アプリを yarn start
コマンドで起動すると、
ブラウザ上に REST API から取得したデータが表示されました。
Spring Boot アプリ、React アプリを停止します。
frontend-app サブプロジェクトで Gradle の build タスクが実行されるようにし、かつ build タスク実行時に yarn build
コマンドが実行されるように設定する
サブプロジェクトに build.gradle を作成すれば Gradle multi-project のサブプロジェクトとして認識されるので、frontend-app の直下に build.gradle を作成し、以下の内容を記述します。
plugins { id "base" id "com.github.node-gradle.node" version "3.0.1" } task yarnBuild(type: YarnTask) { args = ["build"] } build.dependsOn yarnBuild
- base プラグインを追加し、frontend-app サブプロジェクトで build、clean タスクが実行できるようにします。
- gradle-node-plugin プラグインを追加し、build タスク実行時に
yarn build
コマンドが実行されるようにします。
IDEA の Gradle Tool Window で Reload ボタンをクリックすると frontend-app が Gradle のサブプロジェクトとして認識・表示され、その下に build、clean タスクが表示されます。
backend-app サブプロジェクトで build タスク実行時に frontend-app の build 下のファイルを backend-app/src/main/resources/static にコピーされるように設定する
backend-app/build.gradle の一番下に以下の記述を追加します。
.......... clean.delete fileTree("src/main/resources/static").include("**/*") task copyToStatic(type: Copy) { from project(":frontend-app").file("build") into "src/main/resources/static" } copyToStatic.dependsOn ":frontend-app:build" processResources.dependsOn copyToStatic
- clean タスク実行時に src/main/resources/static の下をクリアするように設定します。
- build タスク実行時に、processResources タスクの前で copyToStatic タスクを実行し、frontend-app の build ディレクトリの下にあるディレクトリ・ファイル一式を backend-app/src/main/resources/static の下にコピーします。
IDEA の Gradle Tool Window で Reload ボタンをクリックしておきます。
プロジェクトのルートディレクトリで Gradle の build タスクを実行する
IDEA の Gradle Tool Window から clean → build タスクを実行すると、
:frontend-app:yarnBuild タスクの後に :backend-app:copyToStatic タスクが実行されて、
backend-app/src/main/resources/static の下に React アプリのファイルがコピーされています。
生成された jar ファイルで Spring Boot アプリを起動して動作確認する
コマンドプロンプトで backend-app/build/libs の下に移動してから java -jar backend-app-0.0.1-SNAPSHOT.jar
コマンドを実行して Spring Boot アプリを起動した後、
ブラウザから http://localhost:8080/ にアクセスすると REST API から取得したデータが表示されました。
履歴
2021/04/29
初版発行。
React+Tailwind CSS+Storybook のプロジェクトを作成する(Typescript 版)
概要
記事一覧はこちらです。
React+Tailwind CSS+Storybook のプロジェクトを作成する の Typescript 版を作成します。React+Tailwind CSS+Storybook のプロジェクトを作成する からの差分だけ記述します。
GitHub はこちら
https://github.com/ksby/react-ts-taiwindcss-storybook-sample
参照したサイト・書籍
Storybook - TypeScript
https://storybook.js.org/docs/react/configure/typescriptReact Typescript storybook implement customized Input component with onChange callBack then setState value backTo Input
https://stackoverflow.com/questions/64719744/react-typescript-storybook-implement-customized-input-component-with-onchange-ca.stories.tsx
の書き方はこの QA を参考にしました。
目次
create-react-app ... --template typescript
で react-ts-taiwindcss-storybook-sample プロジェクトを作成する- 「Tailwind CSS をインストールする」~「src/index.css を変更する」は同じ
- src/App.tsx を変更する
- 「npx sb init コマンドを実行して Storybook をインストールする」~「src/stories を削除する」は同じ
- Typescript で component のサンプルを作成して Storybook 上に表示する+Storybook 用の .stories.tsx も Typescript で記述する
手順
create-react-app で react-ts-taiwindcss-storybook-sample プロジェクトを作成する
以下のコマンドを実行し react-ts-taiwindcss-storybook-sample プロジェクトを作成します。
npx create-react-app react-ts-taiwindcss-storybook-sample --template typescript
「Tailwind CSS をインストールする」~「src/index.css を変更する」は同じ
以下の手順は同じです。
- Tailwind CSS をインストールする
- CRACO をインストール・設定する
- npx tailwindcss init -p コマンドを実行して tailwind.config.js、postcss.config.js を作成する
- src/index.css を変更する
src/App.tsx を変更する
src/App.tsx を以下のように変更します。
import { FC } from 'react'; import './App.css'; const App: FC = () => ( <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold"> React+Tailwind CSS </div> ); export default App;
「npx sb init コマンドを実行して Storybook をインストールする」~「src/stories を削除する」は同じ
以下の手順は同じです。
- npx sb init コマンドを実行して Storybook をインストールする
- babel-loader が 8.2.2 にバージョンアップされて yarn start 実行時にエラーが出るので 8.1.0 にバージョンダウンする
- .storybook/preview.js、.storybook/main.js を変更する
- src/stories を削除する
Typescript で component のサンプルを作成して Storybook 上に表示する+Storybook 用の .stories.tsx も Typescript で記述する
Storybook - TypeScript を読むと Storybook は built-in で Typescript をサポートしており、特に追加で設定する必要はない模様。
React Typescript storybook implement customized Input component with onChange callBack then setState value backTo Input を参考に component のサンプルを実装します。
まずは src/components/sample/ListItem.tsx から。
import { FC } from 'react'; export type ListItemProps = { image: string; title: string; author: string; }; const ListItem: FC<ListItemProps> = ({ image, title, author }) => ( <article className="p-2 flex space-x-4"> <img className="flex-none w-16 h-16 rounded-lg" src={image} alt="" /> <div> <dl> <div> <dt className="sr-only">Title</dt> <dd className="text-2xl font-bold">{title}</dd> </div> <div className="mt-0.5"> <dt className="sr-only">Author</dt> <dd className="text-sm font-semibold text-indigo-500">By {author}</dd> </div> </dl> </div> </article> ); export default ListItem;
src/components/sample/ListItem.stories.tsx は以下の内容を記述します。
import React from 'react'; import { Story } from '@storybook/react'; import ListItem, { ListItemProps } from './ListItem'; import dog from './dog.jpg'; export default { title: 'sample/ListItem', component: ListItem, }; const Template: Story<ListItemProps> = (args: ListItemProps) => ( <ListItem image={args.image} title={args.title} author={args.author} /> ); export const Default: Story<ListItemProps> = Template.bind({}); Default.args = { image: dog, title: 'サンプルブック1', author: '作者は犬', };
次は src/components/sample/List.tsx。
import React, { FC } from 'react'; import ListItem, { ListItemProps } from './ListItem'; export type ListProps = { items: ListItemProps[]; }; const List: FC<ListProps> = ({ items }) => ( <ul className="divide-y divide-gray-600"> {items.map((item) => ( <ListItem key={item.title} image={item.image} title={item.title} author={item.author} /> ))} </ul> ); export default List;
src/components/sample/List.stories.tsx は以下の内容を記述します。
import React from 'react'; import { Story } from '@storybook/react'; import List, { ListProps } from './List'; import dog from './dog.jpg'; import cat from './cat.jpg'; import tiger from './tiger.jpg'; export default { title: 'sample/List', component: List, }; const Template: Story<ListProps> = (args: ListProps) => ( <List items={args.items} /> ); export const Default: Story<ListProps> = Template.bind({}); Default.args = { items: [ { image: dog, title: 'サンプルブック1', author: '作者は犬', }, { image: cat, title: 'サンプルブック2', author: '作者は猫', }, { image: tiger, title: 'サンプルブック3', author: '作者はトラ', }, ], };
履歴
2021/04/20
初版発行。
React+Tailwind CSS+Storybook のプロジェクトを作成する
概要
記事一覧はこちらです。
ユーティリティーファーストとTailwind CSSのススメ の記事を読んで React+Tailwind CSS の組み合わせに興味を持ったのでサンプルプロジェクトを作成してみます。作成した Component を確認できるよう Storybook も入れてみます。
Typescript は導入せず Javascript で記述する想定です。
Node.js、npm、yarn は以下のバージョンを使用しています(Node.js と npm のバージョンが古いな。。。とは思いつつ今回はこのままでいきます)。
参照したサイト・書籍
ユーティリティーファーストとTailwind CSSのススメ
https://qiita.com/Takazudo/items/5180f5eb6d798a52074fTailwind CSS
https://tailwindcss.com/tailwindlabs / tailwindcss-forms
https://github.com/tailwindlabs/tailwindcss-formspostcss / postcss - PostCSS 8 for end users
https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users- ツールの PostCSS 8 の対応状況が表示されています。
Install Tailwind CSS with Create React App
https://tailwindcss.com/docs/guides/create-react-appgsoft-inc / craco
https://github.com/gsoft-inc/cracoInstallation
https://tailwindcss.com/docs/installationConfiguration
https://tailwindcss.com/docs/configurationtailwindcss init
コマンドの-p
flag の説明はここに記述されていました。
Storybook
https://storybook.js.org/Install Storybook
https://storybook.js.org/docs/react/get-started/installIntroduction to Storybook for React
https://storybook.js.org/docs/react/get-started/introductionIntegrating React, Tailwind and Storybook
https://johnclarke73.medium.com/integrating-react-tailwind-and-storybook-3ae124aff0d9Storybook-tailwind. How should I add tailwind to storybook
https://stackoverflow.com/questions/65495912/storybook-tailwind-how-should-i-add-tailwind-to-storybook
目次
- create-react-app で react-taiwindcss-storybook-sample プロジェクトを作成する
- Tailwind CSS をインストールする
- CRACO をインストール・設定する
npx tailwindcss init -p
コマンドを実行して tailwind.config.js、postcss.config.js を作成する- src/index.css を変更する
- src/App.css、src/App.js を変更して Tailwind CSS が利用できることを確認する
npx sb init
コマンドを実行して Storybook をインストールする- babel-loader が 8.2.2 にバージョンアップされて
yarn start
実行時にエラーが出るので 8.1.0 にバージョンダウンする - .storybook/preview.js、.storybook/main.js を変更する
- src/stories を削除する
- component のサンプルを作成して Storybook 上に表示する
手順
create-react-app で react-taiwindcss-storybook-sample プロジェクトを作成する
コマンドプロンプトから以下のコマンドを実行し、プロジェクトを作成します。
cd /d/project-react/
npx create-react-app react-taiwindcss-storybook-sample
cd react-taiwindcss-storybook-sample/
yarn test
を実行してテストが正常に終了することを確認します。yarn start
を実行してブラウザに React のロゴが表示されることを確認します。
Tailwind CSS をインストールする
Install Tailwind CSS with Create React App のページを参考に以下のコマンドを実行します。@tailwindcss/forms もインストールします。Tailwind CSS は PostCSS 8 に対応しているのですが create-react-app がまだ対応していないらしく、PostCSS 7 を使うようにする必要があるとのこと。
yarn add tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
※(2021/04/20追記)postcss、autoprefixer はyarn add -D
でインストールした方がよい。yarn add @tailwindcss/forms
CRACO をインストール・設定する
引き続き Install Tailwind CSS with Create React App のページを参考に yarn add @craco/craco
コマンドを実行して CRACO をインストールします。create-react-app の PostCSS の設定を変更するためにこのツールが必要とのこと。
package.json 内の scripts で react-scripts
→ craco
に変更します。
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" },
プロジェクトのルートディレクトリ直下に craco.config.js を作成し、以下の内容を記述します。
module.exports = { style: { postcss: { plugins: [ require('tailwindcss'), require('autoprefixer'), ], }, }, }
npx tailwindcss init -p
コマンドを実行して tailwind.config.js、postcss.config.js を作成する
Installation のページを参考に npx tailwindcss init -p
コマンドを実行して tailwind.config.js、postcss.config.js を作成します。
tailwind.config.js は以下の内容に変更します。
module.exports = { purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [ require('@tailwindcss/forms'), ], }
- purgeに
'./src/**/*.{js,jsx,ts,tsx}', './public/index.html'
を追加します。 - plugins に
require('@tailwindcss/forms'),
を追加します。
postcss.config.js は作成されたままで何も変更しません。
module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }
src/index.css を変更する
src/index.css の中身を全てクリアし、以下の内容に変更します。
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind forms;
src/App.css、src/App.js を変更して Tailwind CSS が利用できることを確認する
Tailwind CSS が利用できるようになっていることを確認します。
src/App.css の中身はどれも使用しないので全てクリアします。
src/App.js を Tailwind CSS を利用して文字列を表示するよう以下の内容に変更します。
import './App.css'; function App() { return ( <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold"> React+Tailwind CSS </div> ); } export default App;
yarn start
を実行すると、
ブラウザに以下のように表示されました。問題なく利用できるようになっています。
npx sb init
コマンドを実行して Storybook をインストールする
Install Storybook のページを参考に npx sb init
コマンドを実行して Storybook をインストールします。
..........
yarn storybook
コマンドを実行して、
..........
Storybook の画面が表示されることを確認します。
babel-loader が 8.2.2 にバージョンアップされて yarn start
実行時にエラーが出るので 8.1.0 にバージョンダウンする
Storybook をインストールした後に yarn start
を実行すると "babel-loader": "8.1.0"
が必要とのエラーが出ます。
yarn.lock を見ると babel-loader が 8.2.2 になっていました。yarn add -D babel-loader@8.1.0
を実行してバージョンダウンします。
バージョンダウン後、再度 yarn start
を実行すると今度は画面が表示されました。
.storybook/preview.js、.storybook/main.js を変更する
Tailwind CSS が適用されるよう .storybook/preview.js、.storybook/main.js を変更します。
.storybook/preview.js を以下のように変更します。
import '../src/index.css'; export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }
import '../src/index.css';
を追加します。
.storybook/main.js を以下のように変更します。Integrating React, Tailwind and Storybook や Storybook-tailwind. How should I add tailwind to storybook を見てコピペしました。
const path = require('path'); module.exports = { "stories": [ "../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/preset-create-react-app" ], webpackFinal: async (config) => { config.module.rules.push({ test: /\,css&/, use: [ { loader: 'postcss-loader', options: { ident: 'postcss', plugins: [ require('tailwindcss'), require('autoprefixer') ] } } ], include: path.resolve(__dirname, '../'), }) return config } }
const path = require('path');
を追加します。webpackFinal: async (config) => { ... }
を追加します。
src/stories を削除する
src/stories に Storybook のサンプルが作成されていますが、不要なので削除します。
component のサンプルを作成して Storybook 上に表示する
src/components/sample ディレクトリを作成し、その下に ListItem.js、List.js の2つの component を作成します。
まずは ListItem.js から。以下の内容を記述します。
import React from 'react'; const ListItem = ({image, title, author}) => ( <article className="p-2 flex space-x-4"> <img className="flex-none w-16 h-16 rounded-lg" src={image} alt=""/> <div> <dl> <div> <dt className="sr-only">Title</dt> <dd className="text-2xl font-bold">{title}</dd> </div> <div className="mt-0.5"> <dt className="sr-only">Author</dt> <dd className="text-sm font-semibold text-indigo-500">By {author}</dd> </div> </dl> </div> </article> ); export default ListItem;
同じ階層に ListItem.stories.js を作成し、以下の内容を記述します。
import React from 'react'; import ListItem from './ListItem'; import dog from './dog.jpg'; export default { title: 'sample/ListItem', component: ListItem, }; const Template = (args) => <ListItem {...args}/>; export const Default = Template.bind({}); Default.args = { image: dog, title: 'サンプルブック1', author: '作者は犬', };
Storybook で ListItem component を表示すると以下のように表示されました。
次は List.js。以下の内容を記述します。
import React from 'react'; import ListItem from "./ListItem"; const List = ({items}) => ( <ul className="divide-y divide-gray-600"> {items.map(item => ( <ListItem key={item.title} {...item}/> ))} </ul> ); export default List;
同じ階層に List.stories.js を作成し、以下の内容を記述します。
import React from 'react'; import List from './List'; import dog from './dog.jpg'; import cat from './cat.jpg'; import tiger from './tiger.jpg'; export default { title: 'sample/List', component: List, }; const Template = (args) => <List {...args}/>; export const Default = Template.bind({}); Default.args = { items: [ { image: dog, title: 'サンプルブック1', author: '作者は犬', }, { image: cat, title: 'サンプルブック2', author: '作者は猫', }, { image: tiger, title: 'サンプルブック3', author: '作者はトラ', }, ] };
Storybook で List component を表示すると以下のように表示されました。
履歴
2021/04/17
初版発行。
2021/04/20
* yarn add babel-loader@8.1.0
→ yarn add -D babel-loader@8.1.0
に変更しました。
* <ListItem {...item}/>
→ <ListItem key={item.title} {...item}/>
に変更しました。
Spring Boot 2.3.x の Web アプリを 2.4.x へバージョンアップする ( その11 )( exclude junit-vintage-engine の記述を削除する+domaGen タスクで SQL ファイルが作成されない問題を解消する )
概要
記事一覧はこちらです。
感想 まで書きましたが、修正が必要な点を見つけたので反映します。
参照したサイト・書籍
目次
- build.gradle から
exclude group: "org.junit.vintage", module: "junit-vintage-engine"
を削除する - domaGen タスクを実行した時に SQL ファイルを作成しない問題を解消する
手順
build.gradle から exclude group: "org.junit.vintage", module: "junit-vintage-engine"
を削除する
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test の記述があったのに build.gradle から不要な記述を削除するのを忘れていました。
build.gradle の testImplementation("org.springframework.boot:spring-boot-starter-test")
に記述していた { exclude group: "org.junit.vintage", module: "junit-vintage-engine" }
を削除します。
dependencies { .......... implementation("io.micrometer:micrometer-registry-prometheus") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") .......... }
domaGen タスクを実行した時に SQL ファイルを作成しない問題を解消する
新規テーブルを作成して domaGen タスクを実行したところ SQL ファイルを生成しないことに気づきました。domaCodeGenDbSql タスクを実行していないことが原因だったので追加します。
// beforeDomaCodeGen --> domaCodeGenDbEntity --> domaCodeGenDbDao --> domaCodeGenDbSql --> domaGen --> afterDomaCodeGen
domaCodeGenDbEntity.dependsOn beforeDomaCodeGen
domaCodeGenDbDao.dependsOn domaCodeGenDbEntity
domaCodeGenDbSql.dependsOn domaCodeGenDbDao
domaGen.dependsOn domaCodeGenDbSql
domaGen.finalizedBy afterDomaCodeGen
domaCodeGenDbSql.dependsOn domaCodeGenDbDao
を追加します。domaGen.dependsOn domaCodeGenDbDao
→domaGen.dependsOn domaCodeGenDbSql
に変更します。
domaGen タスクの全体は以下のようになりました。
// for doma-codegen-plugin // まず変更が必要なもの def rootPackageName = "ksbysample.webapp.lending" def rootPackagePath = "src/main/java/ksbysample/webapp/lending" def dbUrl = "jdbc:postgresql://localhost/ksbylending" def dbUser = "ksbylending_user" def dbPassword = "xxxxxxxx" def dbTableNamePattern = ".*" // おそらく変更不要なもの def packageEntityPath = rootPackagePath + "/entity" def packageDaoPath = rootPackagePath + "/dao" def importOfComponentAndAutowiredDomaConfig = "${rootPackageName}.util.doma.ComponentAndAutowiredDomaConfig" def workPath = "work" def workEntityPath = "${workPath}/entity" def workDaoPath = "${workPath}/dao" task domaGen(group: "doma code generation") { // このタスク自体は何もしない。実行する時の起点用タスクとして作成している。 } task beforeDomaCodeGen { doLast { // 作業用ディレクトリを削除する delete "${workPath}" // 現在の dao, entity パッケージのバックアップを取得する copy() { from "${packageDaoPath}" into "${workDaoPath}/org" } copy() { from "${packageEntityPath}" into "${workEntityPath}/org" } // dao, entity パッケージを削除する delete "${packageDaoPath}" delete "${packageEntityPath}" } } domaCodeGen { db { url = "${dbUrl}" user = "${dbUser}" password = "${dbPassword}" tableNamePattern = "${dbTableNamePattern}" ignoredTableNamePattern = "flyway_schema_history|SPRING_SESSION.*" entity { packageName = "${rootPackageName}.entity" useListener = false useMappedSuperclass = false } dao { packageName = "${rootPackageName}.dao" } } } task afterDomaCodeGen { doLast { // 生成された Entity クラスを作業用ディレクトリにコピーし、 // @SuppressWarnings({"PMD.TooManyFields"}) アノテーションを付加する copy() { from "${packageEntityPath}" into "${workEntityPath}/replace" filter { line -> line.replaceAll('@Entity', '@SuppressWarnings({"PMD.TooManyFields"})\n@Entity') } } // 生成された Dao インターフェースからバックアップにあるクラスを削除する // ※生成済の Dao インターフェースを再生成したい場合には事前に削除すること! for (workDaoFile in new File("${workDaoPath}/org").listFiles()) { def packageDaoFile = new File("${packageDaoPath}/${workDaoFile.name}") if (packageDaoFile.exists()) { packageDaoFile.delete() } } // 生成された Dao インターフェースを作業用ディレクトリにコピーし、 // @ComponentAndAutowiredDomaConfig アノテーションを付加し、 // Javadoc の @param に説明文を追加する copy() { from "${packageDaoPath}" into "${workDaoPath}/replace" filter { line -> line.replaceAll('import org.seasar.doma.Dao;', "import ${importOfComponentAndAutowiredDomaConfig};\nimport org.seasar.doma.Dao;") .replaceAll('@Dao', '@Dao\n@ComponentAndAutowiredDomaConfig') .replaceAll('@param (\\S+)$', '@param $1 $1') } } // 元々 dao, entity パッケージ内にあったファイルを元に戻す copy() { from "${workDaoPath}/org" into "${packageDaoPath}" } copy() { from "${workEntityPath}/org" into "${packageEntityPath}" } // @ComponentAndAutowiredDomaConfig アノテーションを付加した Dao インターフェースを // dao パッケージへ戻す copy() { from "${workDaoPath}/replace" into "${packageDaoPath}" } // @SuppressWarnings({"PMD.TooManyFields"}) アノテーションを付加した Entity クラスを // entity パッケージへ戻す copy() { from "${workEntityPath}/replace" into "${packageEntityPath}" } // 作業用ディレクトリを削除する delete "${workPath}" } } // beforeDomaCodeGen --> domaCodeGenDbEntity --> domaCodeGenDbDao --> domaCodeGenDbSql --> domaGen --> afterDomaCodeGen domaCodeGenDbEntity.dependsOn beforeDomaCodeGen domaCodeGenDbDao.dependsOn domaCodeGenDbEntity domaCodeGenDbSql.dependsOn domaCodeGenDbDao domaGen.dependsOn domaCodeGenDbSql domaGen.finalizedBy afterDomaCodeGen
履歴
2021/04/13
初版発行。
Antora で生成するドキュメントサイトに antora-lunr で検索機能を追加する
概要
記事一覧はこちらです。
antora-lunr を使うと antora で生成するドキュメントサイトに検索機能を追加できると聞いたので、試してみます。
参照したサイト・書籍
Mogztter / antora-lunr
https://github.com/Mogztter/antora-lunrMogztter / antora-site-generator-lunr
https://github.com/Mogztter/antora-site-generator-lunrlunr-languages
https://www.npmjs.com/package/lunr-languagesMihaiValentin / lunr-languages
https://github.com/MihaiValentin/lunr-languagesLANGUAGE SUPPORT
https://lunrjs.com/guides/language_support.html
目次
npm install --save-dev antora-site-generator-lunr
を実行する- ドキュメントサイトを生成して検索機能を試してみる
DOCSEARCH_LANGS=en,ja
やDOCSEARCH_LANGS=ja
を指定してもダメでした。。。- lunr-languages をインストールして日本語で検索できるようにする
DOCSEARCH_INDEX_VERSION=latest
を指定して最新バージョンのドキュメントだけ index が生成されるようにする
手順
npm install --save-dev antora-site-generator-lunr
を実行する
antora-lunr のドキュメントを読むと、簡単に導入するのであれば antora-site-generator-lunr をインストールすればよいとのこと。
ksbysample-antora-playbook プロジェクトで npm install --save-dev antora-site-generator-lunr
を実行して antora-site-generator-lunr をインストールします。
ドキュメントサイトに search component を表示するために antora-playbook.yml を以下のように変更します。
.......... ui: bundle: url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/master/raw/build/ui-bundle.zip?job=bundle-stable snapshot: true supplemental_files: ./node_modules/antora-lunr/supplemental_ui ..........
supplemental_files: ./node_modules/antora-lunr/supplemental_ui
を追加します。
ドキュメントサイトを生成して検索機能を試してみる
build ディレクトリを削除してから DOCSEARCH_ENABLED=true DOCSEARCH_ENGINE=lunr npx antora --generator antora-site-generator-lunr antora-playbook.yml
を実行します。
生成された build ディレクトリを見ると build/site/search-index.js が生成されています。
build/site/index.html をブラウザで開くと search component が画面上部に表示されて、asciidoctor
と入力すると検索結果が表示されました! ただし結果が2重に表示されています。
また日本語で ツール
と入力すると何もヒットしませんでした。
DOCSEARCH_LANGS=en,ja
や DOCSEARCH_LANGS=ja
を指定してもダメでした。。。
Support for other languages の記述があったので、DOCSEARCH_LANGS=en,ja
を追加して DOCSEARCH_ENABLED=true DOCSEARCH_ENGINE=lunr DOCSEARCH_LANGS=en,ja npx antora --generator antora-site-generator-lunr antora-playbook.yml
でドキュメントサイトを生成し直してみましたが、
結果は変わりませんでした。
DOCSEARCH_LANGS=ja
に変更しても結果は変わらず。
lunr-languages をインストールして日本語で検索できるようにする
lunr を日本語で検索できるようにするには lunr-languages をインストールすればよいとの記事を見かけたので、インストールして日本語が検索できるようにしてみます。
まずは npm install --save-dev lunr-languages
を実行して lunr-languages をインストールします。
In a web browser に従い、node_modules/antora-lunr/lib/generate-index.js を以下のように変更します。
'use strict' const lunr = require('lunr') require("lunr-languages/lunr.stemmer.support")(lunr) require('lunr-languages/tinyseg')(lunr) require("lunr-languages/lunr.ja")(lunr) const cheerio = require('cheerio') const Entities = require('html-entities').AllHtmlEntities const entities = new Entities() .......... const lunrIndex = lunr(function () { const self = this self.use(lunr.ja) self.ref('url') ..........
- 以下の3行を追加します。
require("lunr-languages/lunr.stemmer.support")(lunr)
require('lunr-languages/tinyseg')(lunr)
require("lunr-languages/lunr.ja")(lunr)
lunr(function () { ... }
の中に以下の1行を追加します。self.use(lunr.ja)
DOCSEARCH_ENABLED=true DOCSEARCH_ENGINE=lunr npx antora --generator antora-site-generator-lunr antora-playbook.yml
を実行します。
日本語で ツール
と入力すると今度は検索結果が表示されました!
asciidoctor
と入力しても検索結果が表示されます。日本語以外を入力しても問題ないようです。
DOCSEARCH_INDEX_VERSION=latest
を指定して最新バージョンのドキュメントだけ index が生成されるようにする
検索結果が2重に表示されたのは v3.0 と v2.0 の2つのバージョンのドキュメントで index が生成されているためでした。Index only the latest version の記述がありましたので、DOCSEARCH_INDEX_VERSION=latest
を追加して最新バージョンのドキュメントのみ index が生成されるようにします。
最初は DOCSEARCH_INDEX_VERSION=v3.0
と index を生成したい tag を指定するのかと思ったのですが、この設定では結果は何も変わらず、DOCSEARCH_INDEX_VERSION=latest
と指定する必要がありました。
DOCSEARCH_ENABLED=true DOCSEARCH_ENGINE=lunr DOCSEARCH_INDEX_VERSION=latest npx antora --generator antora-site-generator-lunr antora-playbook.yml
を実行します。
日本語で ツール
と入力すると今度は検索結果が1件だけ表示されました。
履歴
2021/03/29
初版発行。