Next.js 5: Universal Webpack、CSS インポート、プラグイン、そしてゾーン
投稿者: Arunoda Susiripala @ arunoda、Tim Neutkens @ timneutkens
Next.js 5.0を世界に向けて発表できることを大変嬉しく思います。npmで即座に利用可能です。
アップグレードするには、以下を実行してください:
npm i next@latest react@latest react-dom@latest
Next.jsのバージョンアップに加えて、peer dependenciesであるreactとreact-domもアップグレードします。
Next.jsは、ユニバーサルでサーバーレンダリング(または静的プリレンダリング)されるReact.jsアプリケーションのためのツールキットです。任意のサイズのアプリケーションの開発を始めるのは、nextを実行するだけで簡単です。
新しいリリースごとに、私たちは後方互換性を保持し、シンプルなアップグレードパスを提供し、絶対に必要な場合にのみAPIの変更を行うことをコミットしています。Next.js 5.0も例外ではありません。
しかし、内部的にはNext.jsは強力な新しいユースケースと拡張性を可能にするために根本的な変革を遂げました。私たちはまず、Next.jsがサーバーとクライアントの両方のコードに対してユニバーサルなWebpackパイプラインを共有するようにしました。
Universal WebpackとNextプラグイン
Next.jsは、Webpack、Babel、Uglifyなどの既存の強力なツールを活用し、エンドユーザーには非常にシンプルなインターフェースとして提供します:next(開発用)、next build(本番用の準備)、next start(サーブ用)、またはnext export(静的ファイルへのプリレンダリング用)。
初期の決定の一つは、これらのツールがどのように設定されるかについて、非常に強力な拡張ポイントを提供することでした。私たちは使いやすさだけでなく、ツールキットを好きなように拡張する柔軟性を可能にしたかったのです。
例えば、next.config.jsでwebpackプロパティを設定することで、Next.jsのwebpack設定を拡張できます。webpackは本番環境と開発環境で異なって実行されるため、当時はデフォルトのwebpack設定を装飾する関数にすることにしました:
module.exports = {
webpack(config, { dev }) {
return config;
},
};
しかし、Webpackはクライアント(ブラウザ)バンドルでのみ実行され、サーバーレンダリングにこの素晴らしいツールチェーンを使用する可能性を逃していました。
私たちは、Webpackをユニバーサルに動作させるためにコードベースを大幅にリファクタリングしたことを発表できて嬉しく思います。あなたの視点からは、上記のデコレータ関数に追加のisServerプロパティが渡されることだけが変更点です。
しかし、新しいセマンティクスは、Webpackローダーの広範なエコシステムが使用可能になることを意味します。
CSS、LESS、SASS、SCSS、CSSモジュール
最も要望の多い機能の一つは、CSSファイルをインポートしてWebpackローダーを活用する機能です:
import './index.css';
export default function Index() {
return (
<div>
<p>I love CSS!</p>
</div>
);
}
これを動作させるには、必要なローダーをpeer dependenciesとして導入できます:
npm i --save css-loader style-loader postcss-loader
これにより、必要なローダーを選択し、異なるバージョンに自由にアップグレードできます。
そして、next.config.jsでローダーを設定するために設定を拡張します:
module.exports = {
webpack(config, options) {
const { dev, isServer } = options;
const extractCSSPlugin = new ExtractTextPlugin({
filename: 'static/style.css',
disable: dev,
});
config.module.rules.push({
test: /\.css$/,
use: cssLoaderConfig(extractCSSPlugin, {
cssModules,
dev,
isServer,
}),
});
return config;
},
};
一般的な推奨事項は、含まれているstyled-jsx babelプラグインのようなコンポーネントローカルスタイリングソリューションを使用することですが、CSSローダーには既存のCSSコードベースの再利用を容易にし、古いコードベースのNext.jsへの移行を大幅に簡素化するなど、多くの重要な強みがあると考えています。
考えられるすべての機能とローダーをデフォルトで有効にする代わりに、設定を装飾するシンプルな関数であるNext.jsプラグインを導入しています。
上記のように手動で設定を拡張してローダーを設定する代わりに、次のようにするだけです:
const withCss = require('next-css');
module.exports = withCss({
});
.cssファイルのインポートを有効にするには、next-cssを導入するだけです。
Next.JSでのCSSローダーの使用について詳しく読むか、すでに作成したパッケージを参照してください:
| ローダー | パッケージ |
|---|
| CSS | next-css |
| LESS | next-less |
| SASS | next-sass |
私たちの目標は、コミュニティが実用的でシンプルな拡張のエコシステムを開発・成長させることを支援することです。そのために、Next.jsコミュニティが維持するnext-pluginsモノレポを開放しています。すべてのPRを歓迎します!
TypeScriptサポート
JavaScriptエコシステムで最も急速に成長している技術の一つがTypeScriptです。Babel 7で公式にサポートされるようになり、.babelrcをカスタマイズするだけでNext.jsでも自然にサポートされることになります。
その間、新しいUniversal Webpackサポートのおかげで、今日すでに完全なTypeScriptサポートを得ることができます!
webpack設定を次のように拡張できます:
module.exports = {
webpack(config, options) {
const { dir, defaultLoaders } = options;
config.resolve.extensions.push('.ts', '.tsx');
config.module.rules.push({
test: /\.+(ts|tsx)$/,
include: [dir],
exclude: /node_modules/,
use: [
defaultLoaders.babel,
{
loader: 'ts-loader',
options: { transpileOnly: true }
},
],
});
return config;
},
};
CSSローダーやプリプロセッサと同様に、TypeScriptは最も要望の多い機能の一つでした。他のローダーと同じように簡単にプロジェクトに組み込めるように、next.config.jsファイルに含めることができるnext-typescriptプラグインを用意しました:
const withTs = require('next-typescript');
module.exports = withTs({
});
プラグインは簡単に組み合わせることができます:それらは単なる関数です。
React代替ライブラリとモジュールオーバーロードのより良いサポート
時間の経過とともに、Reactのドロップイン置換実装が多数登場しました。その中でも注目すべきものには、preact、nervjs、infernoがあります。
他のライブラリは、react-dom-liteのようにDOMレンダラーの置換に焦点を当てており、ブラウザ互換性でいくつかの小さなトレードオフを導入することで、より小さなReactビルドを作ることを目指しています。
Universal Webpackサポートにより、これらのライブラリをドロップイン置換として組み込むプロセスがさらに簡単になります。
他のプラグインと同様に、Next.jsでpreactを使用するために必要なのは次のことだけです:
npm i @zeit/next-preact preact preact-compat
const withPreact = require('@zeit/next-preact');
module.exports = withPreact();
非常にシンプルな@zeit/next-preactモジュールをチェックするか、独自のものを作成してください!
本番環境でのオプション外部ソースマップ
webpackがNext.jsでクライアントとサーバーの両方のコードに使用されるようになったため、本番ビルドでソースマップを有効にすることは、設定への小さな調整だけで済みます。
開発環境ではソースマップが自動的に有効になるため、本番環境では異なって設定します:
module.exports = {
webpack(config, { dev }) {
if (!dev) {
config.devtool = 'source-map';
}
return config;
},
};
ゾーン
Next.jsの最初からの目標の一つは、Webのシンプルさを取り戻し、保持することでした。サーバーレンダリング、データフェッチングへのシンプルで不可知論的なアプローチ、ファイルシステム構造に基づく宣言的ページは、この考えに沿って導入した機能の一部です。
WebサービスやWebサイトの頻繁に見落とされる側面は、それらがいかに自然に構成可能でスケーラブルかということです。例えば、mydomain.com/settingsとmydomain.com/は、独立してデプロイされ、独立してスケールされ、同じソフトウェアの異なるバージョンを実行している、まったく異なる2つのアプリケーションである可能性があります。
エンドユーザーにとって統一された体験に「接着」するために必要なのは、それらを世界に公開するバックエンドルーティング層やロードバランサーのシンプルな設定だけです。
私たちは、通常の<Link>コンポーネントを使用して接続された、Next.jsで構築された複数のアプリケーションを構成する機能を提供できることを非常に嬉しく思います。この機能をゾーンと呼んでいます。
例として、Vercelにデプロイされたこれら2つの独立したNext.jsアプリケーションを考えてみてください:
ドキュメントを刷新した際、コミュニティからの貢献を可能な限り簡単に受け入れられるようにしたいと考えました。ドキュメントの「ミニウェブサイト」を独自のリポジトリに分離することにしました。
さらに、プルリクエストが提出され変更が提案されるたびに、それを自動的に、独立してデプロイします。
最終的に得られたのは2つのゾーンで、path alias機能を使用して親ドメインhttps://vercel.comにまとめられています。次のようになります:
{
"rules": [
{
"pathname": "/docs",
"dest": "our-docs.vercel.app"
},
{
"pathname": "/api",
"dest": "our-docs.vercel.app"
},
{
"dest": "my-main-website.vercel.app"
}
]
}
残りはnow aliasコマンドを実行するだけです:
now alias -r rules.json my-domain.com
私たちの使命は、デプロイメントを可能な限りユニバーサルでオープンにすることです。ローカル開発を支援するために、最近、上記と同じ設定フォーマットで動作するツールであるmicro-proxyをオープンソース化しました。
Nginx、HAProxy、API Gatewayなどの他のソリューションでも同様にゾーンを結合できます。
より高速な本番ビルド時間
私たちは、開発者体験とユーザー体験は密接に関連していると考えています。変更をより効率的に書き、テストし、デプロイできるほど、新機能の追加、バグの修正、全体的なユーザー体験の向上が速くなります。
そのため、システムの最も基本的な構成要素のパフォーマンスプロファイルを継続的に改善することに焦点を当て続けています。
Next.js 5.0では、本番環境へのデプロイやNext.jsアプリケーションを静的サイトとしてエクスポートする前に実行するnext buildコマンドを再検討する機会がありました。
数千のコンポーネントで構成されるReactアプリであるvercel.comについて、Next.js 5.0で23.6%高速な本番ビルド時間という劇的な改善を見ることができたことを報告できて嬉しく思います。
動的インポートの改善されたキャッシュ
動的import()を使用するたびに、これはWebPackに新しいコード分割エントリーポイントが存在することを知らせます。ビルド時には、対応するモジュールのサブツリーに対して特定のバンドルを生成することを意味します。
Next.js 5.0以前では、動的バンドルは次のようなURLを受け取っていました:
/_next/1517592683901/webpack/chunks/components_hello1_1345d10fc951cd6717c5676c467579a6.js
現在では、動的インポートをサブツリーの内容のコンテンツアドレス可能ハッシュに変換しました:
/_next/webpack/chunks/components_hello1_1345d10fc951cd6717c5676c467579a6-b7874680a9e21fb6eb89.js
これは、デプロイメント間で、ユーザーや顧客がすでに使用したコードを不必要に再ダウンロードする必要がないことを意味します。
フラグメント
Next.jsは、各ページでサーバーレンダリングされるトップレベルの<Document>コンポーネントを構築します。このコンポーネントをオーバーロードすることで、マークアップを完全に制御でき、多くの高度なユースケースが可能になります。