はじめに
Aurelia CLIをau run
コマンドを題材に読み砕いて見ていく、という記事です。
私がサーバーサイドエンジニアでフロントエンドの知識が浅いため、
知り得た情報をなるべく細かく書いています。
Aurelia CLI
Aurelia CLIはAureliaを使用する際に便利なコマンド群を提供します。
# 環境
package | version |
---|---|
aurelia-bootstrapper | 2.3.0 |
aurelia-cli | 1.0.0-beta.6 |
テストプロジェクト作成
まずAureliaのプロジェクトを作成してみます
au new
でプロジェクトを作成できます。here
オプションでカレントディレクトリ内に作成してます。
設定は以下の通りです。
tanakeinoMac-puro:aurelia-test tanakei$ au new --here
_ _ ____ _ ___
__ _ _ _ _ __ ___| (_) __ _ / ___| | |_ _|
/ _` | | | | '__/ _ \ | |/ _` | | | | | | |
| (_| | |_| | | | __/ | | (_| | | |___| |___ | |
\__,_|\__,_|_| \___|_|_|\__,_| \____|_____|___|
Which module loader / bundler would you like to use?
1. Webpack (Default)
A powerful and popular bundler for JavaScript
2. CLI's built-in bundler with RequireJS
RequireJS is a mature and stable module loader for JavaScript.
3. CLI's built-in bundler with SystemJS
SystemJS is Dynamic ES module loader, the most versatile module loader for JavaScript
[Webpack]>
What platform are you targeting?
1. Web (Default)
The default web platform setup.
2. ASP.NET Core
A powerful, patterns-based way to build dynamic websites with .NET.
[Web]>
What transpiler would you like to use?
1. Babel (Default)
An open source, standards-compliant ES2015 and ESNext transpiler.
2. TypeScript
An open source, ESNext superset that adds optional strong typing.
[Babel]>
How would you like to setup your template?
1. Default (Default)
No markup processing.
2. Minimum Minification
Removes comments and whitespace between block level elements such as div, blockquote, p, header, footer ...etc
3. Maximum Minification
Removes comments, script & link element [type] attributes and all whitespace between all elements. Also remove attribute quotes where possible.
Collapses boolean attributes.
[Default]>
What css processor would you like to use?
1. None (Default)
Use standard CSS with no pre-processor.
2. Less
Extends the CSS language, adding features that allow variables, mixins, functions and many other techniques.
3. Sass
A mature, stable, and powerful professional grade CSS extension.
4. Stylus
Expressive, dynamic and robust CSS.
5. PostCSS
A tool for transforming CSS with JavaScript.
[None]> 3
Which unit test runners would you like to use?
1. None
Skip testing. My code is always perfect anyway.
2. Karma
Configure your app with Karma and Jasmine
3. Jest
Configure your app with Jest and Jasmine
Select one or more options separated by spaces
> 1
Would you like to configure integration testing?
1. No (Default)
Skip testing. My code is always perfect anyway.
2. Protractor
Configure your app with Protractor
[No]> 1
What is your default code editor?
1. Visual Studio Code (Default)
Code editing. Redefined. Free. Open source. Runs everywhere.
2. Atom
A hackable text editor for the 21st Century.
3. Sublime
A sophisticated text editor for code, markup and prose.
4. WebStorm
A lightweight yet powerful IDE, perfectly equipped for complex client-side development.
5. None of the Above
Do not configure any editor-specific options.
[Visual Studio Code]> 3
Project Configuration
Name: aurelia-test
Platform: Web
Bundler: Webpack
Loader: None
Transpiler: Babel
Markup Processor: None
CSS Processor: Sass
Unit Test Runner: None
Integration Test Runner: None
Editor: Sublime
WARNING: The current directory is not empty. Would you like to create the project in this folder?
1. Yes (Default)
Creates the project structure based on your selections even though the current directory is not empty
2. Restart
Restarts the wizard, allowing you to make different selections.
3. Abort
Aborts the new project wizard.
[Yes]> 1
Project structure created and configured.
Note: lock files are not cross compatible between package managers. Choose Yarn here only if you intend to use Yarn for future package installs. Alternatively, remove either yarn.lock or package-lock.json from the project directory before installing new packages.
Would you like to install the project dependencies?
1. Yes, use Yarn (Default)
Installs all server, client and tooling dependencies needed to build the project using Yarn.
2. Yes, use NPM
Installs all server, client and tooling dependencies needed to build the project using NPM.
3. No
Completes the new project wizard without installing dependencies.
[Yes, use Yarn]> 2
作成後、au run
を押すと...
動いた!
au run
で一体何が起こったのか
ここで本題に入ります。
au run
コマンドを使えば簡単にプロジェクトを実行できるのはわかりました。
Webpackもサーバーサイドも何もいじっていないのに、すごいですね。
だが待ってほしい。
そういうものだ、で形付けるにはあまりにも強引だ。私、気になります。
コマンド詳細
まず、ヘルプを見てみます
run --analyze --env value --hmr
Builds the application and serves up the assets via a local web server, watching files for changes as you work.
--analyze - Enable Webpack Bundle Analyzer. Typically paired with --env prod
--env - Sets the build environment.
--hmr - Enable Hot Module Reload
詳細に見ていきましょう
--analyze
これはWebpack Bundle Analyzer
というものを有効にしています。
Webpackでバンドルしたファイルの内訳を視覚化してくれるツールのようです。
記事あったので貼っておきます
webpackを可視化するツールを紹介#バンドルファイル内の各パッケージがどのくらいの容量を占めているか知りたい
--env
ビルド環境の設定です。
--hmr
これはHot Module Replacement
というものを有効にしています。
これはページをリロードすすることなく更新したコンポーネントを読み込み、描画するという機能です。
通常dev環境ではHot Reload
となり、こちらはファイル変更時にページをリロードするので、コンポーネントのステートが初期化されます。
これも記事あります
Hot Module Replacementの設定と仕組みを理解する
コードを追ってみる
au run
で実行されるコマンドはau new
した際に作成されたaurelia_project/tasks
に含まれています。
tanakeinoMac-puro:aurelia-test tanakei$ cd aurelia_project/tasks/
tanakeinoMac-puro:tasks tanakei$ ls -la
total 72
drwxr-xr-x 11 tanakei staff 352 12 7 00:07 .
drwxr-xr-x 7 tanakei staff 224 12 6 02:34 ..
-rw-r--r-- 1 tanakei staff 1512 12 6 02:25 build.js
-rw-r--r-- 1 tanakei staff 371 12 5 22:57 build.json
-rw-r--r-- 1 tanakei staff 834 12 6 02:46 environment.js
-rw-r--r-- 1 tanakei staff 616 11 30 23:26 jest.js
-rw-r--r-- 1 tanakei staff 250 11 30 23:26 jest.json
-rw-r--r-- 1 tanakei staff 449 11 30 23:26 karma.js
-rw-r--r-- 1 tanakei staff 247 11 30 23:26 karma.json
-rw-r--r-- 1 tanakei staff 1322 12 6 03:16 run.js
-rw-r--r-- 1 tanakei staff 537 12 7 00:07 run.json
run
はrun.js/run.jsonを読んでいるわけです。
run.json
最初にrun.json
を見てみます
{
"name": "test",
"description": "Builds the application and serves up the assets via a local web server, watching files for changes as you work.",
"flags": [
{
"name": "analyze",
"description": "Enable Webpack Bundle Analyzer. Typically paired with --env prod",
"type": "boolean"
},
{
"name": "env",
"description": "Sets the build environment.",
"type": "string"
},
{
"name": "hmr",
"description": "Enable Hot Module Reload",
"type": "boolean"
}
]
}
なるほど、これはヘルプの内容ですね。つまりこれを編集すると...
"description": "僕の考えた最強呪文",
tanakeinoMac-puro:tasks tanakei$ au
run --analyze --env value --hmr
僕の考えた最強呪文
--analyze - Enable Webpack Bundle Analyzer. Typically paired with --env prod
--env - Sets the build environment.
--hmr - Enable Hot Module Reload
おk。次はrun.js
を見ます。
run.js
import {config} from './build';
import configureEnvironment from './environment';
import webpack from 'webpack';
import Server from 'webpack-dev-server';
import project from '../aurelia.json';
import {CLIOptions, reportWebpackReadiness} from 'aurelia-cli';
import gulp from 'gulp';
function runWebpack(done) {
// https://webpack.github.io/docs/webpack-dev-server.html
let opts = {
host: 'localhost',
publicPath: config.output.publicPath,
filename: config.output.filename,
hot: project.platform.hmr || CLIOptions.hasFlag('hmr'),
inline: true,
port: project.platform.port,
contentBase: config.output.path,
historyApiFallback: true,
open: project.platform.open,
stats: {
colors: require('supports-color')
}
};
if (project.platform.hmr || CLIOptions.hasFlag('hmr')) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
config.entry.app.unshift(`webpack-dev-server/client?http://${opts.host}:${opts.port}/`, 'webpack/hot/dev-server');
}
const compiler = webpack(config);
let server = new Server(compiler, opts);
server.listen(opts.port, opts.host, function(err) {
if (err) throw err;
reportWebpackReadiness(opts);
done();
});
}
const run = gulp.series(
configureEnvironment,
runWebpack
);
export { run as default };
コマンドで最初に呼ばれる箇所は
const run = gulp.series(
configureEnvironment,
runWebpack
);
export { run as default };
これですね。run
をdefaultとしています。
gulp.series
でfunctionを順番に処理していきます。
最初のconfigureEnvironment
は
import configureEnvironment from './environment';
environment.js
を読んでいるようです。見てみましょう。
import project from '../aurelia.json';
import rename from 'gulp-rename';
import {CLIOptions} from 'aurelia-cli';
import gulp from 'gulp';
import fs from 'fs';
import path from 'path';
import through from 'through2';
function configureEnvironment() {
let env = CLIOptions.getEnvironment();
return gulp.src(`aurelia_project/environments/${env}${project.transpiler.fileExtension}`)
.pipe(rename(`environment${project.transpiler.fileExtension}`))
.pipe(gulp.dest(project.paths.root))
.pipe(through.obj(function (file, enc, cb) {
// https://github.com/webpack/watchpack/issues/25#issuecomment-287789288
var now = Date.now() / 1000;
var then = now - 10;
fs.utimes(file.path, then, then, function (err) { if (err) throw err });
cb(null, file);
}));
}
export default configureEnvironment;
aurelia_project/environments/<env>.js
のファイルをenvironment.js
にリネームして、project.paths.root
に出力しています。
project.paths.root
はaurelia_project/aurelia.json
に記載されています
...
"paths": {
"root": "src",
...
つまり、初期設定ですとsrc/environment.js
に出力されるわけですね。
run.js
に戻って次はrunWebpack
の処理ですね。
これはrun.js
内部に実装されています。
順番に見てみます。
let opts = {
host: 'localhost',
publicPath: config.output.publicPath,
filename: config.output.filename,
hot: project.platform.hmr || CLIOptions.hasFlag('hmr'),
inline: true,
port: project.platform.port,
contentBase: config.output.path,
historyApiFallback: true,
open: project.platform.open,
stats: {
colors: require('supports-color')
}
};
サーバーの設定のようですね。
hot: project.platform.hmr || CLIOptions.hasFlag('hmr'),
CLIOptions.hasFlag('hmr')
でhmr
オプションをチェックして、HMRを使用するか設定しているわけですね。
ただその前に、project.platform.hmr
があります。
これは先程説明したaurelia.json
から設定を先に取得しています。
次行きます
if (project.platform.hmr || CLIOptions.hasFlag('hmr')) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
config.entry.app.unshift(`webpack-dev-server/client?http://${opts.host}:${opts.port}/`, 'webpack/hot/dev-server');
}
hmr
オプションが有効のときに、webpackにHotModuleReplacementPlugin
を追加しています。
次行きます
const compiler = webpack(config);
let server = new Server(compiler, opts);
server.listen(opts.port, opts.host, function(err) {
if (err) throw err;
reportWebpackReadiness(opts);
done();
});
webpackコンパイラを作成しています。引数のconfig
は
import {config} from './build';
build.jsに設定されているようですね。見てみましょう。
import webpackConfig from '../../webpack.config';
...
const config = webpackConfig({
production, server, extractCss, coverage, analyze
});
...
webpack.config.js
の設定を持ってきているとうわけですね。
戻ります。
webpackコンパイラと、先程のオプションと共にServer
に渡しています。
Server
とは
import Server from 'webpack-dev-server';
なるほど、au run
でwebpack-dev-server
がwebサーバーとして起動していたわけですね。
その後、server.listen
でサーバーを起動して、run.jsの処理は終了です。
reportWebpackReadiness
はwebpack-reporter
という起動ログを表示する関数を叩いています。
https://github.com/aurelia/cli/blob/00ed99754233660f29eb3471f9aad0db9cfe3141/lib/index.js#L12
https://github.com/aurelia/cli/blob/00ed99754233660f29eb3471f9aad0db9cfe3141/lib/build/webpack-reporter.js
おまけ
Aurelia CLI
の挙動について、理解が深まったのではないでしょうか。
他のコマンドも同様に見ていくと面白いと思います。
私も暇ができたら見てみます。
よいAureliaライフを!!!
そして
12/24は🎂古河渚🎂の誕生日です。
皆さん、CLANNADを見ましょう。
さようなら