はじめに
業務の新人施策で、
チーム内で合意形成し、SpringBootをベースにする、
その上で社内で使える技術なら自由に選んでいいよと言われたので、真っ先にnpmが浮かびました。
その理由は、ただjsファイルを用意するだけでなく、
パッケージマネージャーやバンドラーなどの周辺技術を組み合わて、Spring Bootで開発できたらなと思ったからです。
というわけで、とりあえずnpmを入れてみます。
ソースコードはこちらになります。
(コミットメッセージが超適当です。ごめんなさい。)
作成者スペック
- Jsはそこそこに書けるけど、実務の経験はないので客観的にできるとは言えないかも?
- モダンJSはReactもVueも一応書ける
- モジュールバンドラーからは逃げてきました
- Spring Bootはまだまだ学習中のため、本業務で身につけていきたい
- Spring Boot周りの開発技術はもっとわからない、、、頑張って勉強します
SpringBootプロジェクトの開始
前提としてローカルにnpmがある方が便利ですので、npmもとい、Node.jsを用意してやってみてください。
業務のメインはEclipseですが、せっかくなのでvsCodeで始めていこうと思います。
コマンドパレットからSpring Initializer:Create a Gradle Project ...
で作っていきます。
Javaは17系でやってみます。
なお、依存関係は業務でやってるものに合わせました。
plugins {
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
拡張機能はこちらの記事が参考になります。
下記記事を参考(簡単ですが)に、一通り動くものを作ってみます。
今回は下記画像のディレクトリ構造にします。
gradleでnpmを走らせるためのコード
ここからは以下の記事を頼りに(ベースに)環境構築をしました。
業務中はこの記事に幾度となく救われた…ありがたや…
まずはgradleでnpmをビルドできるように、
プラグインを導入した後、コマンドを書いていきます。
plugins {
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
id "com.github.node-gradle.node" version "3.2.1"
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
bootRun {
// for static resource hot reloading
// クラスパスの変更を自動的に監視してくれる
// https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#running-your-application-reloading-resources
sourceResources sourceSets.main
}
repositories {
mavenCentral()
}
node {
// 16系はパッケージとの互換性がない可能性がある
version = '16.14.2'
download = true
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
// task script-name in pacakge-json (dependsOn: ['npm_run_command'])
task webpack(dependsOn: ['npm_run_webpack'])
task dev(dependsOn: ['npm_run_dev'])
task format(dependsOn: ['npm_run_format'])
tasks.named('test') {
useJUnitPlatform()
}
ローカルでpacakage.jsonを作る
ローカルでnpmをinitしてください。
(Npmがローカルにない方はpackage.jsonをゼロから作らないといけません。大変。)
npm init -y
次に必要なパッケージをインストールしていきましょう。
npm install jquery tailwindcss axios
npm install --save-dev @babel/core @babel/preset-env babel-loader webpack webpack-cli webpack-dev-server css-loader sass sass-loader mini-css-extract-plugin path webpack-remove-empty-scripts css-minimizer-webpack-plugin
色々入れました。また、webpackを実行するスクリプトを書いて整えたのが以下のファイルです。
{
"name": "demo",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"webpack": "webpack --mode=development"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tkknot/spring-npm.git"
},
"author": "tkknot",
"license": "ISC",
"bugs": {
"url": "https://github.com/tkknot/spring-npm/issues"
},
"homepage": "https://github.com/tkknot/spring-npm#readme",
"dependencies": {
"axios": "^0.27.2",
"jquery": "^3.6.0",
"tailwindcss": "^3.1.8"
},
"devDependencies": {
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"mini-css-extract-plugin": "^2.6.1",
"node-sass": "^7.0.1",
"path": "^0.12.7",
"sass": "^1.54.4",
"sass-loader": "^13.0.2",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0",
"webpack-remove-empty-scripts": "^0.8.1"
}
}
おそらくnode-sass
やsass-loader
あたりのscssコンパイル周りのバージョンが、
現在のnodeやwebpackのバージョンが適合しない可能性がございますので、こちらはまた後ほど。
style.scssとstyle.cssとmain.jsを作る
表題通りです。以下のパスで作ってください。
- ..(省略)/static/css/style.scss
- ..(省略)/static/css/style.css
- ..(省略)/static/js/main.js
Webpackの設定ファイルを書く
configファイルがないとwebpackを動かせないので、作っていきます。
const webpack = require("webpack");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const RemoveEmptySctiptsPlugin = require("webpack-remove-empty-scripts");
module.exports = {
entry: {
// バンドル対象ファイルが一つの場合
// 生成されるファイル名:対象ファイルの位置
main: path.join(__dirname, "/src/main/resources/static/js/main.js"),
style: path.join(__dirname, "/src/main/resources/static/css/style.scss"),
// バンドル対象のファイルが複数の場合
vendor: [
"axios",
"jquery",
],
},
target: 'node',
// バンドルファイルの出力先
output: {
path: path.join(__dirname, "/src/main/resources/static"), // eslint-disable-line
publicPath: "/",
filename: "js/[name].bundle.js",
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
}),
new MiniCssExtractPlugin({
// cssを別ファイルとして書き出し
filename: "css/[name].css",
}),
// バンドルの際に不要なファイルを削除
new RemoveEmptySctiptsPlugin(),
],
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
],
},
{
test: /\.(sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
// .css 内の URL パスなどをそれぞれの publicPath に合わせてくれる
"css-loader",
// .sass のビルド
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js"],
modules: ["node_modules"],
},
};
以下記事がエラーの解決やCSSを分割する際に役立ちました。
Eslint,Prettierの設定
モダンJS開発では当たり前なコード解析及び整形ツールをこちらでも入れてみます。
npm install --save-dev eslint prettier eslint-plugin-prettier eslint-config-standard eslint-plugin-promise eslint-plugin-import eslint-config-prettier
eslintとprettierは以下で設定ファイルを作ります。
{
"env": {
"node": true,
"es6": true,
"commonjs": true,
"browser": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest"
},
"plugins": ["prettier"],
"extends":[
"eslint:recommended",
"prettier"
],
"rules": {"no-unused-vars": "off"}
}
使われていないモジュールなどに対してエラー判定を出すno-unused-vars
はオフにします。
{
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"quoteProps": "as-needed",
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"bracketSameLine": true
}
整形する必要のないファイルはignoreしましょう。
node_modules
package-lock.json
npmで実行するためのコマンドを書きます。
Eslintで静的解析をし、Prettierで整形という運びになっています。
{
"scripts": {
"webpack": "webpack --mode=development",
//追加
"format" : "eslint --cache --fix src/ && prettier --write src/"
},
}
実行してエラーを吐かなければ成功です。
これで一通りnpmをSpring Boot内で扱えるようになりました!!
npm run format
or
./gradlew format
Scssを用意する
今回は/css
にvariables.scss
という別ファイルを作ってインポートしてみます。
@import "./variables.scss";
header {
color: #ffffff;
background: $color-primary;
}
$color-primary: #36e8ff;
また公式には読み込んでいるJsファイルに.scssファイルをインポートする文を書けとあります。
import '../css/style.scss';
npm run webpack
もしくは./gradlew webpack
をすると、
sass-loaderによってコンパイルしてくれます。
style.css
が以下のようになればOKです
header {
color: #ffffff;
background: #36e8ff;
}
【番外編】できなかったこと
tailwindcssが最大限に使えない
tailwindcssのconfigファイルを作って、package.jsonに実行コマンドを用意しても、
適切に読み込まれず、特定のクラスが使えない、プラグインが使えないなど、、、
tailwindcssが真価を発揮するように実装することができませんでした。
業務の方はBootstrapに変えようかな、、、
一応公式ドキュメントのnpxコマンドでcssファイルは生成できたので、次の項では読み込んでみます。
有識者いらっしゃいましたら教えていただけると幸いです。
簡単な画面を作ってみる
せっかくなので簡単に画面を作ってみましょう。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
<meta charset="utf-8" />
<link rel="stylesheet" th:href="@{/css/tailwind.css}">
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<header class="text-center font-bold"><span th:text="${message}" class="text-lg"></span></header>
<script th:src="@{/js/main.bundle.js}"></script>
</body>
</html>
@import "./variables.scss";
header {
color: #ffffff;
background: $color-primary;
height: 100px;
font-size: 64px;
}
import $ from 'jquery';
$(() => {
console.log('hello');
});
こちらを貼り付けて、npm run webpack
もしくは./gradlew webpack
をすると、
簡単に挨拶をしている画面が出てきます!
コンソールでも挨拶してますね。
(コンソール内のエラーはおそらく拡張機能のものです。)
tailwindcssの諸問題を解消できたので、daisyUIを導入して使ってみる(2022/08/18)
postcss-loaderをwebpackで使えば、postcssのプラグインが動作して、
標準通りtailwindcssが使えます。
せっかくなのでtailwindcssのplugin、daisyUI
を使ってやってみましょう。
npx tailwindcss init -p
npm install --save-dev postcss-loader daisyui
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
<meta charset="utf-8" />
<!-- tailwindcss のスタイルシートを消去 -->
<link rel="stylesheet" th:href="@{/css/style.css}" />
</head>
<body>
<header class="text-center font-bold">
<span th:text="${message}" class="text-5xl"></span>
</header>
<!-- button 追加 -->
<div class="w-full h-24 text-center">
<button class="btn btn-primary">OK</button>
</div>
<script th:src="@{/js/main.bundle.js}"></script>
</body>
</html>
import '../css/style.scss'
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
// daisyuiを呼び出す
plugins: [require('daisyui')],
}
...
new MiniCssExtractPlugin({
// cssを別ファイルとして書き出し
filename: './css/style.css',
}),
...
{
test: /\.(sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
// .css 内の URL パスなどをそれぞれの publicPath に合わせてくれる
'css-loader',
// postcssを使う
'postcss-loader',
// .sass のビルド
'sass-loader',
],
},
...
以下あまりレイアウト整えてませんが、daisyUIも盛り込めました!
なお以下の記事でdaisyUIについて紹介しています(自分が)。
終わりに
正直React+Spring Bootができるなら、
簡単にフロントエンドを動かせる仕組みを導入できたり、サーバーサイドとの分離もしやすいと思うので、
慣れ親しんでる方はそちらのほうがいいなと感じました。
ただ、今回業務内のチームんメンバー全員が開発及びjs初学者・初心者なので、
このようなjs周りが学べる若干レガシーな構成にしました。
ここまで長ったらしい文章を読んでいただきありがとうございました。