diff --git a/ja/build-config.md b/ja/build-config.md new file mode 100644 index 00000000..e5445436 --- /dev/null +++ b/ja/build-config.md @@ -0,0 +1,202 @@ +# ビルド設定 + +クライアントサイドで完結するプロジェクトのwebpack設定は既に知っての通りでしょう。 SSRプロジェクトにおいても大枠は似たようなものですが、設定ファイルを3つのファイル(*base*,*client*,*server*)に分けることを提案しています。base設定は出力パス、エイリアス、ローダーのような、clientとserver両方の環境に共有される設定を含み、server設定とclient設定は単純に、 [webpack-merge](https://github.com/survivejs/webpack-merge)を使って、base設定を拡張することができるものです。 + +## server設定 + +server設定は`createBundleRenderer`に渡されるサーババンドルを生成するために作られるもので、次のようになります: + +```js +const merge = require('webpack-merge') +const nodeExternals = require('webpack-node-externals') +const baseConfig = require('./webpack.base.config.js') +const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') +module.exports = merge(baseConfig, { + // Point entry to your app's server entry file + entry: '/path/to/entry-server.js', + // This allows webpack to handle dynamic imports in a Node-appropriate + // fashion, and also tells `vue-loader` to emit server-oriented code when + // compiling Vue components. + target: 'node', + // For bundle renderer source map support + devtool: 'source-map', + // This tells the server bundle to use Node-style exports + output: { + libraryTarget: 'commonjs2' + }, + // https://webpack.js.org/configuration/externals/#function + // https://github.com/liady/webpack-node-externals + // Externalize app dependencies. This makes the server build much faster + // and generates a smaller bundle file. + externals: nodeExternals({ + // do not externalize dependencies that need to be processed by webpack. + // you can add more file types here e.g. raw *.vue files + // you should also whitelist deps that modifies `global` (e.g. polyfills) + whitelist: /\.css$/ + }), + // This is the plugin that turns the entire output of the server build + // into a single JSON file. The default file name will be + // `vue-ssr-server-bundle.json` + plugins: [ + new VueSSRServerPlugin() + ] +}) +``` + + `vue-ssr-server-bundle.json`が生成されたら、ファイルパスを `createBundleRenderer`に渡します: + +```js +const { createBundleRenderer } = require('vue-server-renderer') +const renderer = createBundleRenderer('/path/to/vue-ssr-server-bundle.json', { + // ...other renderer options +}) +``` + +別の方法として、 バンドルをオブジェクトとして`createBundleRenderer`に渡すことも可能で、これは開発中のホットリロードに対して便利です。 参考として [HackerNewsの設定](https://github.com/vuejs/vue-hackernews-2.0/blob/master/build/setup-dev-server.js) を見てみてください。 + +### externalsの注意 + + CSSファイルを`externals`オプションにホワイトリスト登録していることに注目してください。その理由は、依存関係からインポートされるCSS はwebpackによって処理されないといけないからです。 もし同じようにwebpackに依存する他のタイプのファイルをインポートしているなら、 (例: `*.vue`, `*.sass`)、 それらも同じようにホワイトリストに加えなければいけません。 + +ホワイトリスト登録する他のタイプのモジュールは、例えば `babel-polyfill`のような`global`を修正するポリフィルです。なぜなら、サーババンドルの中のコードは独自の ** `global` **オブジェクトを持っているからです。Node7.6以降を使っていればサーバに`babel-polyfill`はあまり必要ないので、単純にクライアントエントリーにインポートする方が簡単です。 + +## client設定 + +client設定はbase設定とほぼ同じままです。言うまでもなく、クライアント側のエントリーファイルに`entry`を示す必要があります。またそれとは別に、もし`CommonsChunkPlugin`使っていたら、それがclient設定だけで使われていることを確認しておかないといけません。なぜなら、サーババンドルは単一のエントリーチャンクを要求するからです。 + +### `clientManifest` の作成 + +> 必須 version 2.3.0以降 + +サーババンドルに加えて、クライアントビルドマニフェストを作成することもできます。レンダラーは、クライアントマニフェストとサーババンドルでサーバ側*と*クライアント側の両方のビルド情報を持つことになり、 レンダリングされたHTMLに[preload / prefetch directives](https://css-tricks.com/prefetching-preloading-prebrowsing/)やCSSのlinkやscriptタグを自動的に挿入することができます。 + +これには2重の恩恵があります: + +1. 生成されたファイル名にハッシュがある時に、正しいURLを注入する`html-webpack-plugin` の代替になります。 +2. webpackのオンデマンドコード分割機能(code spliting)を利用するバンドルをレンダリングする時に、最適なチャンクがpreloaded / prefetchedされるのを保証でき、かつ、クライアントに対するウォーターフォールリクエストを避けるために、必要な非同期チャンクに``タグを挿入することができます。そのようにしてTTI (time-to-interactive)が改善します。 + +クライアントマニフェストを利用するためには、client設定はこのようになります: + +```js +const webpack = require('webpack') +const merge = require('webpack-merge') +const baseConfig = require('./webpack.base.config.js') +const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') +module.exports = merge(baseConfig, { + entry: '/path/to/entry-client.js', + plugins: [ + // Important: this splits the webpack runtime into a leading chunk + // so that async chunks can be injected right after it. + // this also enables better caching for your app/vendor code. + new webpack.optimize.CommonsChunkPlugin({ + name: "manifest", + minChunks: Infinity + }), + // This plugins generates `vue-ssr-client-manifest.json` in the + // output directory. + new VueSSRClientPlugin() + ] +}) +``` + +これで、作成されたクライアントマニフェストをページテンプレートと一緒に利用できるようになります。 + +```js +const { createBundleRenderer } = require('vue-server-renderer') +const template = require('fs').readFileSync('/path/to/template.html', 'utf-8') +const serverBundle = require('/path/to/vue-ssr-server-bundle.json') +const clientManifest = require('/path/to/vue-ssr-client-manifest.json') +const renderer = createBundleRenderer(serverBundle, { + template, + clientManifest +}) +``` + +この設定で、コード分割されたビルドのためにサーバ側でレンダリングされるHTMLはこのようになります(すべて自動でインジェクトされます)。 + +```html + + + + + + + + + + + +