Symfonyで、JavascriptやCSSなどフロントエンドのアセットを管理する仕組みとして、以前はAsseticが用意されていましたが、Webpackを利用するWebpack Endoreに置き替わり今時な構成になりました。
Laravelで言うところのElixirにあたります。
Webpack Encoreの利用方法については、公式ドキュメント Managing CSS and JavaScript に一通りの使い方が載っています。
また、Symfonyのでもアプリ symfony/symfony-demo が、Webpack Encoreを使った構成になっているので、こちらのソースを読むほうが解りやすいかもしれません。
この記事では、公式ドキュメントの例、First Example を試してみた手順をまとめいます。
公式ドキュメントでは、nodeのパッケージ管理システムにyarn
を使っていますが、私は普段まだnpm
を使っているので、npm
を利用してパッケージをインストールしています。
プロジェクトの構成
symfony/symfony-demo を参考に、以下のようなディレクトリ構成にします
$ tree -L 2
.
├── app
├── assets
│ ├── css
│ └── js
├── node_modules
├── package.json
├── package-lock.json
├── src
├── tests
├── var
├── vendor
├── web
│ └── build
└── webpack.config.js
追加しているディレクトリ・ファイルは以下のとおりです。
assets/js
: Javascriptのソースを配置assets/css
: CSS(SCSS)のソースを配置node_modules
: ローカルインストールされるnpmパッケージを保存、npm install
コマンド実行で自動生成されるwebpack.config.js
: webpackの設定package.json
: npmのプロジェクト設定ファイルpckage-lock.json
: 依存npmパッケージ ロックファイルweb/build
Webpackを実行して、バンドルされたファイルが出力されるディレクトリ
プロジェクトの準備
Symfonyのプロジェクトを用意します
$ composer create-project symfony/framework-standard-edition symfony-webpack-encore
$ cd symfony-webpack-encore
アセットのソースを配置するディレクトリを作成します
$ mkdir assets
$ mkdir assets/js
$ mkdir assets/css
Webpack Encoreのインストール
Webpack Encoreはnpmパッケージとして提供されています。
npm init
してから、@symfony/webpack-encore
をインストールします。
$ npm init -y
$ npm install @symfony/webpack-encore --save-dev
package.json
とpackage-lock.json
ファイルが生成されます。
補足: npmを利用する場合は、npm init
を実行してpackage.json
を生成しておく必要があります
package.json
が無いとencore
コマンド実行時にCannot determine webpack context.
とエラーになります。
webpack.config.jsの作成
Webpackの設定ファイル webpack.config.js
を作成します
以下は、First ExampleのConfiguring Encore/Webpackのコードからスタイルシート関連を削除したものです。
// webpack.config.js
var Encore = require('@symfony/webpack-encore');
Encore
// バンドルされたアセットが出力されるディレクトリ
.setOutputPath('web/build/')
// `outputPath`の公開版パス (プロジェクトのドキュメントルートからの相対パスを指定)
.setPublicPath('/build')
// ビルドする前に`outputPath`に指定したディレクトリを空にする
.cleanupOutputBeforeBuild()
// エントリファイルの指定、バンドルされたファイルは`web/build/app.js`として出力される
.addEntry('app', './assets/js/main.js')
// jQueryをProvidePluginでグローバルに利用できるようにするかどうか
.autoProvidejQuery()
.enableSourceMaps(!Encore.isProduction())
;
// export the final configuration
module.exports = Encore.getWebpackConfig();
Webpackをそのまま使うより簡潔に記述できますが、Webpackそのものは理解をしていないと設定は難しそうです。
サンプル実装
Requiring JavaScript Modulesに記述されているコードで動作を確認してみます
バンドルしたファイルを読み込むテンプレート
デフォルトのレイアウトテンプレートbase.html.twig
でバンドルしたcss、jsを読み込むようにします
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
{% block body %}{% endblock %}
<script src="{{ asset('build/app.js') }}"></script>
</body>
</html>
JSモジュールとエントリーファイル
文字列を返すだけのシンプルな関数を含むモジュールを記述し、CommonJSスタイルでexportします
// assets/js/greet.js
module.exports = function(name) {
return `Yo yo ${name} - welcome to Encore!`;
};
このgreet.js
を利用するmain.js
を以下のように記述します
// assets/js/main.js
// loads the jquery package from node_modules
var $ = require('jquery');
// import the function from greet.js (the .js extension is optional)
// ./ (or ../) means to look for a local file
var greet = require('./greet');
$(document).ready(function() {
$('h1').html(greet('john'));
});
DOMへのレンダリングはjQueryを利用していますので、npmでjqueryをインストールしておきます
$ npm install jquery --save-dev
ビルドして動作確認
以下のコマンドでビルドします。
$ ./node_modules/.bin/encore dev
Running webpack ...
DONE Compiled successfully in 1006ms 10:12:35
I 2 files written to web/build
サーバーを起動
$ bin/console server:run
ブラウザで表示してみると、いつものスタートアップページの上部にJavascriptで追加した「Yo yo john – welcome to Encore!」が表示されたことを確認できます。
SCSSのコンパイル
次にSCSSのコンパイル設定も確認しておきます。
公式ドキュメント CSS Preprocessors: Sass, LESS, etc.のUsing Sassを参考にWebpackの環境をセットアップします。
パッケージを追加
Webpackのsass-loaderをインストールします
$ npm install sass-loader node-sass --save-dev
webpack.config.js
webpack.config.js
にsass-loader
の有効化と、SCSSのエントリーファイルの指定を追加します
// webpack.config.js
var Encore = require('@symfony/webpack-encore');
Encore
// ...
// CSSのエントリーファイル、コンパイルし`web/build/main.css`ファイルとして出力
.addStyleEntry('main', './assets/css/main.scss')
// sass-loaderを有効化
.enableSassLoader()
//...
;
サンプル
h1のテキストを赤くするだけの簡単なSCSSファイルで確認してみます
// assets/css/main.scss
$header-color: red !default;
h1 {
color: $header-color;
}
テンプレートにbuild/main.css
の読み込みを追加
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<!-- ... -->
<link rel="stylesheet" href="{{ asset('build/main.css') }}">
</head>
<!-- ... -->
</html>
動作確認
再度ビルドし直してブラウザで確認すると以下のように、h1の色が赤く表示されました
TypeScriptのコンパイル
おまけですが、TypeScriptの導入も確認してみます。
公式ドキュメントのセットアップ手順は、Enabling TypeScript (ts-loader)に記述されています。
パッケージの追加
typescript
とts-loader
をインストールします
$ npm install typescript ts-loader --save-dev
webpack.config.jsの修正
webpack.config.js
にmain.js
のエントリーをmain.ts
に変更し、enableTypeScriptLoader
でTypeScriptのコンパイルを有効化します。
// webpack.config.js
// ...
Encore
// ...
.addEntry('app', './assets/js/main.ts')
.enableTypeScriptLoader()
TypeScirptのコンパイルオプションの設定ファイルtsconfig.json
を以下のように作成します
// tsconfig.json
{
"compilerOptions": {
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react",
"lib" : ["es2015", "es2015.iterable", "dom"]
},
"include": [
"./assets/js/**/*"
]
}
サンプル実装をTypeScriptで書き換え
サンプルはjQueryを利用しているので、TypeScriptの型定義をインストールする必要があります
$ npm install jquery @types/jquery --save-dev
jsは拡張子をtsに変更して、以下のようにTypeScriptに書き換えます
// assets/js/main.ts
import * as $ from 'jquery';
import greet from './greet';
$(document).ready(function() {
$('h1').html(greet('john'));
});
// assets/js/greet.ts
export default function(name:string) {
return `Yo yo ${name} - welcome to Encore!`;
};
動作確認
encore
コマンドを実行し直します
$ ./node_modules/.bin/encore dev
Running webpack ...
DONE Compiled successfully in 2149ms 23:58:21
I 3 files written to web/build
動作は同じです