Webpack(Typescript、Sass)フロントエンド開発環境
Rustと関連クレートをインストールしたら、アプリケーションプロジェクトを作成します。
通常のRustプロジェクトであれば、cargo init [project name]
とするのですが、Tauri開発環境ではフロントエンドとの同時進行開発となるので、まずはプロジェクトのトップディレクトリの作成から
$ mkdir [project name]
$ cd [project name]
として作業を始めます。ここではプロジェクト名を単純に「proj」としておきます。
次に下記コマンド cargo tauri init
で対話的にプロジェクトを作成します。
- プロジェクト名
- タイトル
- フロントエンドのアセットディレクトリ。生成されるRustプロジェクトからの相対パスとなるので、../dist の様にする。
この中にあるindex.htmlがフロントエンドデザインの起点となる
- 開発用サーバーの設定。上記アセットと同じパスにしても良いが、本番構成と同じTauiの内部サーバーを使用するので毎回コンパイルが必要となるため、開発用サーバーを立ち上げてそのURLを記載する方が便利かも。(後述のwebpack-dev-server)を使用するのが良いと思います。
proj$ cargo tauri init
What is your app name? · [project name]
What should the window title be? · [project name]
? Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that w
Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that will be created? · ../dist
What is the url of your dev server? · ../dist または http://localhost:8080
プロジェクト名その他は後からでも変更可能のようです。(src-tauri/tairu.conf.json)
設定したアセットディレクトリと、その中にindex.htmlを作成します。内容はとりあえずテンプレート的な感じで。(VScodeなら1文字目に’!’を入力して[tab]キーでドーンとテンプレートが入力されます)
proj$ mkdir dist
proj$ touch dist/index.html
proj
├── dist
│ └── index.html
└── src-tauri
├── Cargo.lock
├── Cargo.toml
├── build.rs
├── icons
│ ├── 128x128.png
│ ├── ........
│ ├── 32x32.png
│ ├── icon.icns
│ ├── icon.ico
│ └── icon.png
├── src
│ └── main.rs
└── tauri.conf.json
ここまでのディレクトリ構成は左のようになります。
src-tauri以下がRustのプロジェクトです。dist以下がフロントエンドを構成するアセットディレクトリで、ここからWEBアプリと同様なノリで進めることが出来ます。
ちなみにこの段階で、tauriアプリとしてコンパイル&実行が出来ます。
しかし、まだ真っ白なウインドウだけのアプリですが・・・・w
また、プロジェクト初期化の段階で開発サーバーにhttp://localhostとか設定していた場合は、まだサーバーを立ち上げていないので何も起こりません。
ここからフロントエンドの開発環境を整えます。まずはプロジェクトのトップディレクトリでnodejsの初期化と必要なものを色々とインストールします
proj$ npm init -y
proj$ npm install --save-dev webpack webpack-cli webpack-dev-server
proj$ npm install --save-dev typescript sass ts-loader sass-loader css-loader
proj$ npm install --save-dev postcss-loader style-loader
proj$ npm install --save-dev @tauri-apps/api @tauri-apps/cli
片っ端からインストールしている感じがしないでもないですが、これだけあれば足りるでしょうか。
次にTypescriptの初期化。この辺は好みがあるかもなので、テキトウに。。。
proj$ npx tsc --init --target es6 --module ES2020 --lib ES2020,DOM --sourceMap true --moduleResolution node --allowSyntheticDefaultImports true --resolveJsonModule true
webpack.config.jsも通常のWEBアプリと同様の設定としました。
webpack.config.js
const path = require("path");
module.exports = {
mode: "development",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader"
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: function () {
return [require('autoprefixer')];
}
}
}
},
{
loader: 'sass-loader'
}
]
},
{
test:/\.xml$/,
loader: 'xml-loader',
},
{
test:/\.html$/,
loader: 'html-loader',
},
{
test:/\.SVG$/,
//loader: 'svg-inline-loader'
type: 'asset/source',
},
{
// https://ics.media/entry/16329/
test:/.(gif|svg|png|jpg|jpeg|JPG)$/,
// type: 'asset/inline',
type: 'asset', /** default <8kb: inline, >8kb: resource */
generator: {
filename: 'image/[hash].[ext]',
}
},
{
test:/.(mp3|wav|aac)$/,
type: 'asset/resource',
generator: {
filename: 'audio/[hash].[ext]'
}
},
{
test:/.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'font/[hash].[ext]'
}
}
]
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json", ".wasm"]
},
experiments: {
outputModule: true,
asyncWebAssembly: true,
},
devServer: {
static: {
directory: path.join(__dirname, 'dist')
},
port: 8080,
}
}
webpackはデフォルトではソースはsrc/index.js、生成物はdist/main.mjs(モジュール版)となっているので、上記のファイル構成に対してトップへsrcディレクトリを追加します
proj$ mkdir src
proj$ touch src/index.js
そしてdist/index.htmlに埋め込むために次の一行をHEADの最後に追加
<script type="module" src="./main.mjs"></script>
package.jsonに実行環境のスクリプトを追加
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server"
},
src-tauri/tauri.config.json を変更
- beforeBuildCommand : Build前に実行されるコマンド、この場合Webpackコンパイルのみ
- beforeDevCommand:デバッグ時に事前に実行されるコマンド。webpack-dev-server起動、webpackコンパイルもリアルタイムに行われる。
- devPath:webpack-dev-serverに置き換える。これによりデバッグ状態でもフロントエンドの編集がリアルタイムに反映されるようになる
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:8080/",
"distDir": "../dist"
},
しかし、実際のデバッグはVScode上で行われるので、.vscodeディレクトリと各種設定を行う(VScodeのデバッグでは上記tauri.config.jsonは使われないようです)
proj
├── .vscode
│ ├── launch.json
│ └── tasks.json
└── src-tauri
・・・・・
.vscode/*
launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Tauri Development Debug",
"cargo": {
"args": [
"build",
"--manifest-path=./src-tauri/Cargo.toml",
"--no-default-features"
]
},
// task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
"preLaunchTask": "dist:dev"
},
{
"type": "lldb",
"request": "launch",
"name": "Tauri Production Debug",
"cargo": {
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
},
// task for the `beforeBuildCommand` if used, must be configured in `.vscode/tasks.json`
"preLaunchTask": "dist:build"
}
]
}
tasks.json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "dist:dev",
"type": "shell",
// `dev` keeps running in the background
// ideally you should also configure a `problemMatcher`
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
"isBackground": true,
// change this to your `beforeDevCommand`:
"command": "yarn",
"args": ["dev"],
},
{
"label": "dist:build",
"type": "shell",
// change this to your `beforeBuildCommand`:
"command": "yarn",
"args": ["build"],
}
]
}
コレで、VScodeで開発・デバッグが出来るようになりました。
フロントエンドの開発が殆どWEBアプリのそれと同じなのが良いですね。ていうか、特にバックエンドの要らないアプリだとjavascriptだけでデスクトップアプリが出来てしまうという。逆に殆どをRsutによるバックエンドだけにしてもアプリケーションを構成出来たり、アプリの用途や開発者の好みでどちら寄りにも出来てしまいそうなのが面白い。