apeescape2.com
  • メイン
  • Uiデザイン
  • Webフロントエンド
  • ヒントとツール
  • データサイエンスとデータベース
技術

WebpackまたはBrowserify&Gulp:どちらが良いですか?

Webアプリケーションがますます複雑になるにつれて、Webアプリをスケーラブルにすることが最も重要になります。以前はアドホックJavaScriptとjQueryを作成するだけで十分でしたが、現在、Webアプリを構築するには、次のようなはるかに高度な規律と正式なソフトウェア開発手法が必要です。

  • コードへの変更が既存の機能を壊さないことを確認するための単体テスト
  • エラーのない一貫したコーディングスタイルを保証するためのリンティング
  • 開発ビルドとは異なる本番ビルド

Webには、独自の開発上の課題もいくつかあります。たとえば、ウェブページは多くの非同期リクエストを行うため、ウェブアプリのパフォーマンスは、それぞれ独自の小さなオーバーヘッド(ヘッダー、ハンドシェイクなど)を持つ数百のJSファイルとCSSファイルをリクエストする必要があるために大幅に低下する可能性があります。この特定の問題は、多くの場合、ファイルをバンドルすることで解決できるため、数百の個別のファイルではなく、単一のバンドルされたJSファイルとCSSファイルのみをリクエストします。

バンドルツールのトレードオフ:WebpackとBrowserify

WebpackまたはBrowserify + Gulpのどちらのバンドルツールを使用する必要がありますか?これが選択のガイドです。 つぶやき

また、ES5の互換性を維持しながらES6コードを活用するために、ネイティブJSやCSSにコンパイルされるSASSやJSXなどの言語プリプロセッサやBabelなどのJSトランスパイラーを使用することもよくあります。

これは、Webアプリ自体のロジックの記述とは関係のないかなりの数のタスクに相当します。ここでタスクランナーが登場します。タスクランナーの目的は、これらすべてのタスクを自動化して、アプリの作成に集中しながら、強化された開発環境から利益を得ることができるようにすることです。タスクランナーを構成したら、ターミナルで1つのコマンドを呼び出すだけです。

使用します gulp 非常に開発者にやさしく、習得が容易で、すぐに理解できるため、タスクランナーとして。

Gulpの簡単な紹介

GulpのAPIは、次の4つの関数で構成されています。

C言語でのオペレーティングシステムプログラミング
  • gulp.src
  • gulp.dest
  • gulp.task
  • gulp.watch

Gulpのしくみ

たとえば、次の4つの関数のうち3つを使用するサンプルタスクを次に示します。

gulp.task('my-first-task', function() { gulp.src('/public/js/**/*.js') .pipe(concat()) .pipe(minify()) .pipe(gulp.dest('build')) });

my-first-taskの場合が実行され、グロブパターンに一致するすべてのファイル/public/js/**/*.js縮小されてからbuildに転送されますフォルダ。

これの美しさは.pipe()にありますチェーン。入力ファイルのセットを取得し、それらを一連の変換にパイプしてから、出力ファイルを返します。さらに便利にするために、minify()などの実際の配管変換は、多くの場合NPMライブラリによって実行されます。その結果、パイプ内のファイルの名前を変更する以外に、独自の変換を作成する必要があることは実際には非常にまれです。

Gulpを理解するための次のステップは、タスクの依存関係の配列を理解することです。

gulp.task('my-second-task', ['lint', 'bundle'], function() { ... });

ここで、my-second-task lintの後にのみコールバック関数を実行しますおよびbundleタスクが完了しました。これにより、関心の分離が可能になります。LESSの変換など、単一の責任を持つ一連の小さなタスクを作成します。 CSSに移動し、タスクの依存関係の配列を介して他のすべてのタスクを呼び出すだけの一種のマスタータスクを作成します。

最後に、gulp.watchがあります。これは、globファイルパターンの変更を監視し、変更が検出されると、一連のタスクを実行します。

gulp.task('my-third-task', function() { gulp.watch('/public/js/**/*.js', ['lint', 'reload']) })

上記の例では、/public/js/**/*.jsに一致するファイルへの変更lintをトリガーしますおよびreload仕事。 gulp.watchの一般的な使用法これは、ブラウザでライブリロードをトリガーすることです。これは、開発に非常に役立つ機能であり、一度体験すると、それなしでは生きていけません。

そして、そのように、あなたはgulpについて本当に知る必要があるすべてを理解しています。

Webpackはどこに収まりますか?

Webpackのしくみ

CommonJSパターンを使用する場合、JavaScriptファイルをバンドルすることはそれらを連結することほど簡単ではありません。むしろ、一連のindex.jsを持つエントリポイント(通常はapp.jsまたはrequireと呼ばれます)があります。またはimportファイルの先頭にあるステートメント:

ES5

var Component1 = require('./components/Component1'); var Component2 = require('./components/Component2');

ES6

import Component1 from './components/Component1'; import Component2 from './components/Component2';

app.jsの残りのコードの前に依存関係を解決する必要があり、それらの依存関係自体にさらに解決すべき依存関係がある場合があります。さらに、あなたはrequireかもしれませんアプリケーションの複数の場所で同じ依存関係がありますが、その依存関係を解決したいのは1回だけです。ご想像のとおり、依存関係ツリーが数レベル深くなると、JavaScriptをバンドルするプロセスはかなり複雑になります。これは、 Browserify とWebpackが入ります。

開発者がGulpの代わりにWebpackを使用しているのはなぜですか?

Webpack はバンドラーですが、Gulpはタスクランナーであるため、これら2つのツールが一般的に一緒に使用されることを期待できます。代わりに、特にReactコミュニティの間で、Webpackを使用する傾向が高まっています。 代わりに ガルプの。どうしてこれなの?

簡単に言えば、Webpackは非常に強力なツールであるため、タスクランナーを介して実行するタスクの大部分をすでに実行できます。たとえば、Webpackには、バンドルの縮小化とソースマップのオプションがすでに用意されています。さらに、Webpackは、ライブリロードとホットリロードの両方をサポートするwebpack-dev-serverと呼ばれるカスタムサーバーを介してミドルウェアとして実行できます(これらの機能については後で説明します)。ローダーを使用することで、ES6からES5へのトランスパイル、およびCSSプリプロセッサとポストプロセッサを追加することもできます。それは本当に、Webpackが独立して処理できない主要なタスクとしてユニットテストとリンティングを残すだけです。少なくとも半ダースの潜在的なgulpタスクを2つに削減したことを考えると、多くの開発者は代わりにNPMスクリプトを直接使用することを選択します。これにより、プロジェクトにGulpを追加するオーバーヘッドが回避されます(これについては後で説明します)。 。

Webpackを使用することの主な欠点は、構成がかなり難しいことです。これは、プロジェクトをすばやく立ち上げて実行しようとしている場合は魅力的ではありません。

3つのタスクランナーのセットアップ

3つの異なるタスクランナー設定でプロジェクトを設定します。各セットアップは、次のタスクを実行します。

  • 監視対象のファイル変更をライブでリロードする開発サーバーをセットアップする
  • 監視対象のファイル変更に対してスケーラブルな方法でJSおよびCSSファイル(ES6からES5への変換、SASSからCSSへの変換およびソースマップを含む)をバンドルします
  • スタンドアロンタスクとして、または監視モードで単体テストを実行します
  • lintingをスタンドアロンタスクとして、またはウォッチモードで実行します
  • ターミナルで1つのコマンドを使用して、上記のすべてを実行する機能を提供します
  • 縮小化やその他の最適化を使用して本番バンドルを作成するための別のコマンドがあります

3つのセットアップは次のようになります。

  • Gulp + Browserify
  • Gulp + Webpack
  • Webpack + NPMスクリプト

アプリケーションは使用します React フロントエンド用。もともとはフレームワークにとらわれないアプローチを使用したかったのですが、Reactを使用するとHTMLファイルが1つだけ必要であり、ReactはCommonJSパターンで非常にうまく機能するため、実際にはタスクランナーの責任が簡素化されます。

各セットアップの長所と短所について説明しますので、プロジェクトのニーズに最適なセットアップのタイプについて情報に基づいた決定を下すことができます。

アプローチごとに1つずつ、3つのブランチを持つGitリポジトリをセットアップしました( リンク )。各セットアップのテストは次のように簡単です。

git checkout npm prune (optional) npm install gulp (or npm start, depending on the setup)

各ブランチのコードを詳しく調べてみましょう…

共通コード

フォルダ構造

- app - components - fonts - styles - index.html - index.js - index.test.js - routes.js

index.html

単純なHTMLファイル。 Reactアプリケーションがロードされ、バンドルされたJSファイルとCSSファイルを1つだけ使用します。実際、Webpack開発のセットアップでは、bundle.cssも必要ありません。

index.js

これは、アプリのJSエントリポイントとして機能します。基本的に、Reactルーターをdivにロードするだけです。 ID付きapp先に述べたように。

routers.js

このファイルはルートを定義します。 URL /、/aboutおよび/contact HomePage、AboutPage、およびContactPageにマップされますそれぞれコンポーネント。

index.test.js

llcのさまざまな種類は何ですか

これは、ネイティブJavaScriptの動作をテストする一連の単体テストです。実際の本番品質のアプリでは、Reactコンポーネント(少なくとも状態を操作するコンポーネント)ごとに単体テストを作成し、React固有の動作をテストします。ただし、この投稿では、ウォッチモードで実行できる機能ユニットテストを用意するだけで十分です。

components / App.js

これは、すべてのページビューのコンテナと考えることができます。各ページには、コンポーネントと、ページビュー自体に評価されるthis.props.childrenが含まれています(例:ブラウザのContactPageにある場合)。

components / home / HomePage.js

これが私たちのホームビューです。 /contactを使用することを選択しましたブートストラップのグリッドシステムはレスポンシブページの作成に優れているためです。ブートストラップを適切に使用すると、小さいビューポート用に作成する必要のあるメディアクエリの数が大幅に削減されます。

残りのコンポーネント(react-bootstrap、Header、AboutPage)も同様に構造化されています(ContactPageマークアップ、状態操作なし)。

それでは、スタイリングについて詳しく説明しましょう。

CSSスタイリングアプローチ

Reactコンポーネントのスタイルを設定するための私の好ましいアプローチは、コンポーネントごとに1つのスタイルシートを用意することです。そのスタイルは、その特定のコンポーネントにのみ適用されるようにスコープされています。私のReactコンポーネントのそれぞれで、トップレベルのreact-bootstrapに気付くでしょう。コンポーネントの名前と一致するクラス名があります。したがって、たとえば、divマークアップは次のようにラップされています。

HomePage.js

関連する ... もあります次のように構成されたファイル:

HomePage.scss

このアプローチがなぜそれほど役立つのですか?その結果、高度にモジュール化されたCSSが実現し、不要なカスケード動作の問題が大幅に解消されます。

2つのReactコンポーネント@import '../../styles/variables'; .HomePage { // Content here } があるとします。およびComponent1。どちらの場合も、Component2をオーバーライドする必要がありますフォントサイズ。

h2

/* Component1.scss */ .Component1 { h2 { font-size: 30px; } } /* Component2.scss */ .Component2 { h2 { font-size: 60px; } } h2のフォントサイズおよびComponent1コンポーネントが隣接しているか、一方のコンポーネントが他方の内部にネストされているかに関係なく、は独立しています。理想的には、これはコンポーネントのスタイリングが完全に自己完結型であることを意味します。つまり、コンポーネントはマークアップのどこに配置されていてもまったく同じように見えます。実際には、それは必ずしもそれほど単純ではありませんが、それは確かに正しい方向への大きな一歩です。

Rubyのレールとは

コンポーネントごとのスタイルに加えて、Component2が好きです。グローバルスタイルシートstylesと、特定の責任を処理するSASSパーシャル(この場合、フォントと変数のそれぞれglobal.scssと_fonts.scss)を含むフォルダー。グローバルスタイルシートを使用すると、アプリ全体の一般的なルックアンドフィールを定義できます。ヘルパーパーシャルは、必要に応じてコンポーネントごとのスタイルシートでインポートできます。

各ブランチの共通コードについて詳しく説明したので、最初のタスクランナー/バンドラーアプローチに焦点を移しましょう。

Gulp + Browserify Setup

gulpfile.js

これは、22のインポートと150行のコードを含む驚くほど大きなgulpfileになります。したがって、簡潔にするために、_variables.scss、js、css、server、およびwatchのみを確認します。タスクの詳細。

JSバンドル

default

このアプローチは、いくつかの理由でかなり醜いです。一つには、タスクは3つの別々の部分に分割されます。まず、Browserifyバンドルオブジェクト// Browserify specific configuration const b = browserify({ entries: [config.paths.entry], debug: true, plugin: PROD ? [] : [hmr, watchify], cache: {}, packageCache: {} }) .transform('babelify'); b.on('update', bundle); b.on('log', gutil.log); (...) gulp.task('js', bundle); (...) // Bundles our JS using Browserify. Sourcemaps are used in development, while minification is used in production. function bundle() { return b.bundle() .on('error', gutil.log.bind(gutil, 'Browserify Error')) .pipe(source('bundle.js')) .pipe(buffer()) .pipe(cond(PROD, minifyJS())) .pipe(cond(!PROD, sourcemaps.init({loadMaps: true}))) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)); } を作成し、いくつかのオプションを渡し、いくつかのイベントハンドラーを定義します。次に、Gulpタスク自体があります。これは、名前付き関数をインライン化するのではなく、コールバックとして渡す必要があります(bはまったく同じコールバックを使用するため)。これには、b.on('update')を渡すだけのGulpタスクの優雅さはほとんどありません。いくつかの変更をパイプします。

もう1つの問題は、これにより、gulp.src、htmlをリロードするためのさまざまなアプローチが必要になることです。およびcssブラウザで。私たちのGulpを見てjs仕事:

watch

HTMLファイルが変更されると、gulp.task('watch', () => { livereload.listen({basePath: 'dist'}); gulp.watch(config.paths.html, ['html']); gulp.watch(config.paths.css, ['css']); gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); }); タスクが再実行されます。

html

最後のパイプ呼び出しgulp.task('html', () => { return gulp.src(config.paths.html) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); }); livereload()の場合はNODE_ENVではなく、ブラウザの更新をトリガーします。

同じロジックがCSSウォッチにも使用されます。 CSSファイルが変更されると、productionタスクが再実行され、cssの最後のパイプが実行されますタスクトリガーcssブラウザを更新します。

ただし、livereload()時計はjsを呼び出しませんまったくタスク。代わりに、Browserifyのイベントハンドラーjsまったく異なるアプローチ(つまり、ホットモジュールの交換)を使用してリロードを処理します。このアプローチの不一致は苛立たしいものですが、残念ながら 増分 ビルドします。単純にb.on('update', bundle)と呼んだ場合livereload()の終わりに関数、これは再構築します 全体 個々のJSファイルの変更に関するJSバンドル。このようなアプローチは明らかに拡張性がありません。 JSファイルが多いほど、各リバンドルにかかる時間が長くなります。突然、500ミリ秒のリバンドルに30秒かかり始めます。これは、アジャイル開発を実際に阻害します。

CSSバンドル

bundle

ここでの最初の問題は、面倒なベンダーのCSSの組み込みです。新しいベンダーのCSSファイルがプロジェクトに追加されるたびに、要素をgulp.task('css', () => { return gulp.src( [ 'node_modules/bootstrap/dist/css/bootstrap.css', 'node_modules/font-awesome/css/font-awesome.css', config.paths.css ] ) .pipe(cond(!PROD, sourcemaps.init())) .pipe(sass().on('error', sass.logError)) .pipe(concat('bundle.css')) .pipe(cond(PROD, minifyCSS())) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); }); に追加するようにgulpfileを変更することを忘れないでください。実際のソースコードの関連する場所にインポートを追加するのではなく、配列。

もう1つの主な問題は、各パイプの複雑なロジックです。 gulp.srcというNPMライブラリを追加する必要がありましたパイプに条件付きロジックを設定するだけで、最終結果はあまり読みにくくなります(どこでもトリプルブラケット!)。

サーバータスク

gulp-cond

このタスクは非常に簡単です。これは基本的に、gulp.task('server', () => { nodemon({ script: 'server.js' }); }); を実行するコマンドライン呼び出しnodemon server.jsのラッパーです。ノード環境で。 server.js nodemonの代わりに使用されますファイルに変更を加えると、ファイルが再起動します。デフォルトでは、nodeで実行中のプロセスを再開します どれか JSファイルの変更。そのため、nodemonを含めることが重要です。その範囲を制限するファイル:

nodemon.json

サーバーコードを確認しましょう。

server.js

{ 'watch': 'server.js' }

これにより、ノード環境に基づいてサーバーとポートのベースディレクトリが設定され、expressのインスタンスが作成されます。

const baseDir = process.env.NODE_ENV === 'production' ? 'build' : 'dist'; const port = process.env.NODE_ENV === 'production' ? 8080: 3000; const app = express();

これによりapp.use(require('connect-livereload')({port: 35729})); app.use(express.static(path.join(__dirname, baseDir))); が追加されますミドルウェア(ライブリロードのセットアップに必要)と静的ミドルウェア(静的アセットの処理に必要)。

connect-livereload

これは単純なAPIルートです。 app.get('/api/sample-route', (req, res) => { res.send({ website: 'ApeeScape', blogPost: true }); }); に移動した場合ブラウザに次のように表示されます。

localhost:3000/api/sample-route

実際のバックエンドでは、APIルート専用のフォルダー全体、DB接続を確立するための個別のファイルなどがあります。このサンプルルートは、設定したフロントエンドの上にバックエンドを簡単に構築できることを示すために含まれているだけです。

{ website: 'ApeeScape', blogPost: true }

これはキャッチオールルートです。つまり、ブラウザに入力したURLに関係なく、サーバーは唯一のapp.get('*', (req, res) => { res.sendFile(path.join(__dirname, './', baseDir ,'/index.html')); }); を返します。ページ。その場合、クライアント側でルートを解決するのはReactルーターの責任です。

index.html

これは、指定したポートをリッスンし、指定したURLの新しいタブでブラウザーを開くようにExpressインスタンスに指示します。

これまでのところ、サーバーのセットアップについて私が気に入らないのは次のとおりです。

app.listen(port, () => { open(`http://localhost:${port}`); });

すでにapp.use(require('connect-livereload')({port: 35729})); を使用していることを考えるとgulpfileでは、これにより、livereloadを使用する必要がある2つの別々の場所が作成されます。

さて、最後になりましたが、重要なことです。

デフォルトのタスク

gulp-livereload

これは、単にgulp.task('default', (cb) => { runSequence('clean', 'lint', 'test', 'html', 'css', 'js', 'fonts', 'server', 'watch', cb); }); と入力したときに実行されるタスクです。ターミナルに。奇妙なことに、gulpを使用する必要がありますタスクを順番に実行するため。通常、一連のタスクは並行して実行されますが、これが常に望ましい動作であるとは限りません。たとえば、runSequenceが必要です。タスクはcleanの前に実行されますファイルを移動する前に、宛先フォルダーが空であることを確認します。 gulp 4がリリースされると、htmlがサポートされます。およびgulp.seriesメソッドはネイティブですが、今のところ、セットアップにこのわずかな癖を残しておく必要があります。

それを超えて、これは実際にはかなりエレガントです。アプリの作成とホスティング全体が1つのコマンドで実行され、ワー​​クフローの任意の部分を理解することは、実行シーケンスで個々のタスクを調べるのと同じくらい簡単です。さらに、シーケンス全体を小さなチャンクに分割して、アプリを作成およびホストするためのよりきめ細かいアプローチをとることができます。たとえば、gulp.parallelという別のタスクを設定できます。 validateを実行しますおよびlintタスク。または、testを使用することもできます実行されるタスクhostおよびserver。タスクをオーケストレーションするこの機能は、特にアプリケーションが拡張され、より自動化されたタスクが必要になるため、非常に強力です。

開発と本番ビルド

watch

if (argv.prod) { process.env.NODE_ENV = 'production'; } let PROD = process.env.NODE_ENV === 'production'; を使用するNPMライブラリでは、コマンドラインフラグをGulpに提供できます。ここでは、yargsの場合、ノード環境を本番環境に設定するようにgulpfileに指示します。 --prodに渡されますターミナルで。私たちのgulp次に、変数は、gulpfileの開発動作と本番動作を区別するための条件として使用されます。たとえば、PRODに渡すオプションの1つ構成は次のとおりです。

browserify

これはplugin: PROD ? [] : [hmr, watchify] を示します本番モードでプラグインを使用せず、browserifyを使用するおよびhmr他の環境のプラグイン。

これwatchify条件付きは、本番環境と開発用に別々のgulpfileを作成する必要がなく、最終的には多くのコードの繰り返しが含まれるため、非常に便利です。代わりに、PRODのようなことができます本番環境でデフォルトのタスクを実行するには、またはgulp --prod gulp html --prodのみを実行します生産におけるタスク。一方、Gulpパイプラインにhtmlなどのステートメントが散らばっているのは以前に見ました。最も読みやすいものではありません。結局、ブール変数アプローチを使用するか、2つの別々のgulpfileを設定するかは好みの問題です。

次に、Gulpをタスクランナーとして使用し続け、BrowserifyをWebpackに置き換えるとどうなるかを見てみましょう。

ソフトウェアプロジェクトのドキュメントを準備する方法

Gulp + Webpackのセットアップ

突然、gulpfileの長さはわずか99行で、インポートは12回になり、以前の設定から大幅に削減されました。デフォルトのタスクを確認すると、次のようになります。

.pipe(cond(!PROD, livereload()))

これで、完全なWebアプリのセットアップに必要なタスクは9つではなく5つになり、劇的に改善されました。

さらに、gulp.task('default', (cb) => { runSequence('lint', 'test', 'build', 'server', 'watch', cb); }); の必要性を排除しました。私たちのlivereloadタスクは単純になりました:

watch

これは、gulpwatcherがいかなる種類の再バンドル動作もトリガーしていないことを意味します。追加のボーナスとして、転送する必要はありませんgulp.task('watch', () => { gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); }); index.htmlから〜appまたはdistもう。

タスクの削減に焦点を戻すと、build、html、cssおよびjsタスクはすべて単一のfontsに置き換えられました仕事:

build

十分に単純です。 gulp.task('build', () => { runSequence('clean', 'html'); return gulp.src(config.paths.entry) .pipe(webpack(require('./webpack.config'))) .pipe(gulp.dest(config.paths.baseDir)); }); を実行しますおよびclean順番にタスク。それらが完了したら、エントリポイントを取得し、Webpackにパイプして、htmlを渡します。ファイルを構成して、結果のバンドルをwebpack.config.jsに送信します(ノード環境に応じて、baseDirまたはdistのいずれか)。

Webpack構成ファイルを見てみましょう。

webpack.config.js

これはかなり大きくて威圧的な設定ファイルなので、buildに設定されている重要なプロパティのいくつかを説明しましょう。オブジェクト。

module.exports

これにより、Webpackが使用するソースマップのタイプが設定されます。 Webpackは、すぐに使用できるソースマップをサポートするだけでなく、実際にはさまざまなソースマップオプションをサポートしています。各オプションは、ソースマップの詳細と再構築速度(変更時に再バンドルするのにかかる時間)のバランスが異なります。これは、開発に「安価な」ソースマップオプションを使用して高速リロードを実現し、本番環境ではより高価なソースマップオプションを使用できることを意味します。

devtool: PROD ? 'source-map' : 'eval-source-map',

これがバンドルのエントリポイントです。配列が渡されることに注意してください。つまり、複数のエントリポイントを持つことができます。この場合、予想されるエントリポイントがありますentry: PROD ? './app/index' : [ 'webpack-hot-middleware/client?reload=true', // reloads the page if hot module reloading fails. './app/index' ] 同様にapp/index.jsホットモジュールのリロード設定の一部として使用されるエントリポイント。

webpack-hot-middleware

これは、コンパイルされたバンドルが出力される場所です。最も紛らわしいオプションはoutput: { path: PROD ? __dirname + '/build' : __dirname + '/dist', publicPath: '/', filename: 'bundle.js' }, です。バンドルがサーバー上でホストされる場所のベースURLを設定します。したがって、たとえば、publicPathの場合がpublicPathの場合、バンドルは/public/assetsの下に表示されますサーバー上。

/public/assets/bundle.js

これにより、プロジェクト内のどのフォルダをサーバーのルートディレクトリとして使用するかがサーバーに指示されます。

Webpackがプロジェクトで作成されたバンドルをサーバー上のバンドルにどのようにマッピングしているかについて混乱した場合は、次の点に注意してください。

  • devServer: { contentBase: PROD ? './build' : './app' } + path:プロジェクトのソースコード内のバンドルの正確な場所
  • filename (ルートとして、contentBase)+ /:サーバー上のバンドルの場所
publicPath

これらは、Webpackの機能を何らかの方法で強化するプラグインです。たとえば、plugins: PROD ? [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.DefinePlugin(GLOBALS), new ExtractTextPlugin('bundle.css'), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) ] : [ new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ], 縮小に責任があります。

webpack.optimize.UglifyJsPlugin

これらはローダーです。基本的に、loaders: [ {test: /.js$/, include: path.join(__dirname, 'app'), loaders: ['babel']}, { test: /.css$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap'): 'style!css?sourceMap' }, { test: /.scss$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap!resolve-url!sass?sourceMap') : 'style!css?sourceMap!resolve-url!sass?sourceMap' }, gif)(?S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]', woff2 ] を介してロードされたファイルを前処理します。ステートメント。ローダーをチェーン接続できるという点で、Gulpパイプにいくぶん似ています。

ローダーオブジェクトの1つを調べてみましょう。

require()

{test: /.scss$/, loader: 'style!css?sourceMap!resolve-url!sass?sourceMap'} プロパティは、ファイルが指定された正規表現パターン(この場合はtest)に一致する場合に、指定されたローダーが適用されることをWebpackに通知します。 /.scss$/プロパティは、ローダーが実行するアクションに対応します。ここでは、loader、style、cssをチェーンしています。およびresolve-url逆の順序で実行されるローダー。

sassが見つからないことを認めなければなりません構文は非常にエレガントです。結局のところ、プログラムの中で右から左に何かを読まなければならないのはいつですか。それにもかかわらず、ローダーはwebpackの非常に強力な機能です。実際、先ほど触れたローダーを使用すると、SASSファイルをJavaScriptに直接インポートできます。たとえば、ベンダーとグローバルスタイルシートをエントリポイントファイルにインポートできます。

index.js

loader3!loader2!loader1

同様に、ヘッダーコンポーネントにimport React from 'react'; import {render} from 'react-dom'; import {Router, browserHistory} from 'react-router'; import routes from './routes'; // CSS imports import '../node_modules/bootstrap/dist/css/bootstrap.css'; import '../node_modules/font-awesome/css/font-awesome.css'; import './styles/global.scss'; render(, document.getElementById('app')); を追加できます。コンポーネントに関連付けられたスタイルシートをインポートします。これは、他のすべてのコンポーネントにも当てはまります。

私の意見では、これはJavaScript開発の世界における革命的な変化とほぼ見なすことができます。 ローダーがこれらすべてを処理するため、CSSのバンドル、ミニファイ、またはソースマップについて心配する必要はありません。ホットモジュールのリロードでさえ、CSSファイルで機能します。次に、同じファイルでJSとCSSのインポートを処理できるため、開発が概念的に単純になります。一貫性が高まり、コンテキストの切り替えが少なくなり、推論が容易になります。

この機能の仕組みを簡単に説明すると、WebpackはCSSをJSバンドルにインライン化します。実際、Webpackは画像やフォントに対してもこれを行うことができます。

import './Header.scss'

URLローダーはWebpackに、画像とフォントが100 KB未満の場合はデータURLとしてインライン化し、それ以外の場合は個別のファイルとして提供するように指示します。もちろん、カットオフサイズを10KBなどの別の値に構成することもできます。

これがWebpackの構成です。かなりの量のセットアップがあることは認めますが、それを使用することの利点は単に驚異的です。 Browserifyにはプラグインと変換がありますが、追加機能の点でWebpackローダーと比較することはできません。

Webpack + NPMスクリプトのセットアップ

このセットアップでは、タスクの自動化にgulpfileに依存するのではなく、npmスクリプトを直接使用します。

package.json

gif)(?S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]', ttf)(?S*)?$/, loader: 'url?limit=100000&name=fonts/[name].[ext]'

開発ビルドと本番ビルドを実行するには、'scripts': { 'start': 'npm-run-all --parallel lint:watch test:watch build', 'start:prod': 'npm-run-all --parallel lint test build:prod', 'clean-dist': 'rimraf ./dist && mkdir dist', 'clean-build': 'rimraf ./build && mkdir build', 'clean': 'npm-run-all clean-dist clean-build', 'test': 'mocha ./app/**/*.test.js --compilers js:babel-core/register', 'test:watch': 'npm run test -- --watch', 'lint': 'esw ./app/**/*.js', 'lint:watch': 'npm run lint -- --watch', 'server': 'nodemon server.js', 'server:prod': 'cross-env NODE_ENV=production nodemon server.js', 'build-html': 'node tools/buildHtml.js', 'build-html:prod': 'cross-env NODE_ENV=production node tools/buildHtml.js', 'prebuild': 'npm-run-all clean-dist build-html', 'build': 'webpack', 'postbuild': 'npm run server', 'prebuild:prod': 'npm-run-all clean-build build-html:prod', 'build:prod': 'cross-env NODE_ENV=production webpack', 'postbuild:prod': 'npm run server:prod' } と入力しますそれぞれnpm start。

これは、99〜150行のコードを19 NPMスクリプトに削減したことを考えると、gulpfileよりも確かにコンパクトです。本番スクリプトを除外した場合は12行になります(ほとんどの場合、ノード環境が本番環境に設定された開発スクリプトをミラーリングします)。 )。欠点は、これらのコマンドが、Gulpタスクの対応するコマンドと比較してやや不可解であり、表現力がそれほど高くないことです。たとえば、(少なくとも私が知っている限りでは)単一のnpmスクリプトで特定のコマンドを直列に実行し、他のコマンドを並列に実行する方法はありません。どちらか一方です。

ただし、このアプローチには大きな利点があります。 npm run start:prodなどのNPMライブラリを使用するコマンドラインから直接、それぞれに同等のGulpラッパーをインストールする必要はありません(この場合、mocha)。

NPMをインストールする代わりに

  • フライエスリント
  • gulp-mocha
  • gulp-nodemon
  • 等

次のパッケージをインストールします。

  • スリング
  • モカ
  • nodemon
  • 等

コーリーハウスの投稿を引用して、 NPMスクリプトのためにGulpとGruntを残した理由 :

私はGulpの大ファンでした。しかし、私の最後のプロジェクトでは、gulpfileに数百行と約12のGulpプラグインが含まれることになりました。 Gulpを使用して、Webpack、Browsersync、ホットリロード、Mochaなどを統合するのに苦労していました。どうして?さて、いくつかのプラグインは私のユースケースには不十分なドキュメントを持っていました。一部のプラグインは、必要なAPIの一部のみを公開していました。 1つには、少数のファイルしか監視しないという奇妙なバグがありました。コマンドラインに出力するときに別のストリップされた色。

彼はGulpの3つの主要な問題を指定しています。

  1. プラグインの作者への依存
  2. デバッグするのにイライラする
  3. ばらばらのドキュメント

私はこれらすべてに同意する傾向があります。

国境調整税対関税

1.プラグイン作成者への依存

gulp-mochaなどのライブラリはいつでも更新され、関連するeslintライブラリには対応する更新が必要です。ライブラリメンテナが興味を失った場合、ライブラリのgulpバージョンはネイティブバージョンと同期しなくなります。新しいライブラリが作成されるときも同じことが言えます。誰かがライブラリを作成した場合gulp-eslintそれに追いつくと、突然、対応するxyzが必要になりますgulpタスクで使用するライブラリ。

ある意味で、このアプローチは拡張性がありません。理想的には、ネイティブライブラリを使用できるGulpのようなアプローチが必要です。

2.デバッグにイライラする

gulp-xyzなどのライブラリはこの問題を大幅に軽減するのに役立ちますが、それでもgulp-plumberでのエラー報告は事実です。あまり役に立ちません。 1つのパイプでも未処理の例外がスローされると、ソースコードで問題の原因とはまったく関係がないと思われる問題のスタックトレースが取得されます。これにより、デバッグが悪夢になる場合があります。エラーが不可解であるか、誤解を招く可能性がある場合、GoogleやStackOverflowで検索しても実際には役に立ちません。

3.ばらばらのドキュメント

しばしば私はそれが小さいことに気づきますgulpライブラリのドキュメントは非常に限られている傾向があります。これは、著者が通常、主に自分で使用するためにライブラリを作成しているためだと思います。さらに、Gulpプラグインとネイティブライブラリ自体の両方のドキュメントを確認する必要があるのが一般的です。つまり、多くのコンテキスト切り替えと2倍の読み取りが必要になります。

結論

それぞれのオプションには長所と短所がありますが、BrowserifyよりもWebpackの方が、GulpよりもNPMスクリプトの方が望ましいことは私にはかなり明らかです。 Gulpは確かにNPMスクリプトよりも表現力があり便利ですが、追加されたすべての抽象化で代償を払うことになります。

すべての組み合わせがアプリに最適であるとは限りませんが、圧倒的な数の開発依存関係と苛立たしいデバッグエクスペリエンスを回避したい場合は、NPMスクリプトを使用したWebpackが最適です。この記事が、次のプロジェクトに適したツールを選択するのに役立つことを願っています。

関連:
  • 制御の維持:WebpackとReactのガイド、Pt。 1
  • Gulp Under the Hood:ストリームベースのタスク自動化ツールの構築

ApeeScapeはGuidantGlobalと提携して、フリーランサーのエリートネットワークへのオンデマンドアクセスを提供します

その他

ApeeScapeはGuidantGlobalと提携して、フリーランサーのエリートネットワークへのオンデマンドアクセスを提供します
CloudKitのガイド:iOSデバイス間でユーザーデータを同期する方法

CloudKitのガイド:iOSデバイス間でユーザーデータを同期する方法

モバイル

人気の投稿
Figma vs. Sketch vs. Axure –タスクベースのレビュー
Figma vs. Sketch vs. Axure –タスクベースのレビュー
簡単な方法でERC20トークンを作成する方法
簡単な方法でERC20トークンを作成する方法
Reduxフォームライブラリの作成者からのフルスタック開発者向けのヒント
Reduxフォームライブラリの作成者からのフルスタック開発者向けのヒント
シニアフロントエンドエンジニア、クライアントポータルチーム
シニアフロントエンドエンジニア、クライアントポータルチーム
スワイプ可能なUITabBarをゼロから作成する方法
スワイプ可能なUITabBarをゼロから作成する方法
 
ReactフックとTypeScriptの操作
ReactフックとTypeScriptの操作
iOSおよびAndroidデザインでの悪い習慣の回避
iOSおよびAndroidデザインでの悪い習慣の回避
フラグメントナビゲーションパターンに関するAndroidデベロッパーガイド
フラグメントナビゲーションパターンに関するAndroidデベロッパーガイド
進化する絵文字:メッセージングの新しい顔のためのデザイン
進化する絵文字:メッセージングの新しい顔のためのデザイン
ブログを高コンバージョントンネルに変換するための5ステップのプロセス
ブログを高コンバージョントンネルに変換するための5ステップのプロセス
人気の投稿
  • ソフトウェアプロジェクト管理におけるコスト見積もり
  • ヘクタールあたりのアブラヤシの収量
  • グーグルクラウド自然言語API
  • adobexdとは何ですか
  • githubフローとgitフロー
カテゴリー
仕事の未来 革新 人とチーム その他 モバイル 製品の担当者とチーム 技術 計画と予測 製品ライフサイクル ツールとチュートリアル

© 2021 | 全著作権所有

apeescape2.com