- 投稿日:2021-02-28T23:41:37+09:00
Reduxの環境を5分で構築しよう!
Reduxの環境を5分で構築しよう!
Reduxの環境を5分で構築する方法を記します。
Reduxとは
Redux(リダックス)とは、Reactにおけるコンポーネントの状態を管理する機能を提供するライブラリです。
今回のゴール
Node.jsをインストールし、Reactプロジェクトを作成し、ReactプロジェクトにReduxをインストールすること
OS情報
- Windows10
構築手順
Node.jsをインストール
https://nodejs.org/ja/にアクセスし、推奨版をダウンロードします。
標準設定でインストールする場合は、デフォルトのまま「Next」をクリックすればよいです。Reactプロジェクトを作成
コマンドプロンプトを開き、任意のディレクトリにReactプロジェクトを作成します。
npx create-react-app <project_name>
と入力します。Reduxのインストール
作成したプロジェクトにReduxをインストールします。
まず作成したプロジェクトのルート階層へ移動します。
npm install --save redux
と入力します。React Reduxのインストール
「React Redux」というパッケージをインストールすることで、ReactプロジェクトでReduxを使用できるようになります。
npm install --save react-redux
と入力します。まとめ
以上の手順でReduxが使用できるようになりました。
新しくプロジェクトを作成する際には、1の手順は飛ばし、2~4の手順で作成しましょう。おわり
- 投稿日:2021-02-28T17:16:55+09:00
node.jsでデータベースをherokuに接続できないの解決法
Unable to connect to the database: ConnectionError [SequelizeConnectionError]: self signed certificate上記エラーが出たときloaderに下記コードを追加したら治りました。
dialectOptions: { ssl: { require: true, rejectUnauthorized: false // <<<<<< YOU NEED THIS } }
- 投稿日:2021-02-28T17:01:22+09:00
TypeGraphQLでN+1問題を解決した話
はじめに
GraphQLをサービスで使い始めて、N+1問題にぶち当たったのでその解決策を紹介する。
プロジェクト構成
- Node.js
- TypeScript
- Express
- GraphQL(Apollo, TypeGraphQL)
実際何が起こったか
DBにはとあるレコードが入っており、それぞれに
userid
を保持している。
userid
からユーザー名やメアドなどのユーザー情報を取り出すには、別の内部APIに問い合わせる必要がある。GraphQLのスキーマはこのように定義している。
schema.gqltype Query { record(id: Int!): Record records(name: String): [Record!]! } type Record { id: Int! name: String! user: User userid: Int! } type User { userid: Int! username: String! }レコードはこのように取得しているとする。
RootResolver.ts@Resolver() export class RootResolver { @Query(returns => [Record]) async records(): Promise<Record[]> { const records = await conn.query(` SELECT id, name, userid FROM xxx `); return records; } @Query(returns => Record, { nullable: true }) async record( @Arg('id', type => Int) id: number ): Promise<Record | undefined> { const records = await conn.query(` SELECT id, name, userid FROM xxx WHERE id = ? `, [id]); return records[0]; } }このとき、N+1問題を気にせずに
user
リゾルバを書くことこのようになる。
fetchUsers
は内部APIにリクエストを送ってユーザー情報を返す関数とする。@Resolver(of => Record) class RecordResolver { @FieldResolver() user(@Root() record: Record) { return fetchUsers([record.userid])[0]; } }例えば
Record
を1件だけ取得する場合は、内部APIへのリクエストは1回で済むが、
一覧画面などで100件取得する場合はfetchUsers
がほぼ同時に100回呼ばれることとなり、内部APIサーバーやDBの負荷が上がってしまう。10件取得した場合のログ
fetchUsers(0) fetchUsers(1) fetchUsers(2) fetchUsers(3) fetchUsers(4) fetchUsers(5) fetchUsers(6) fetchUsers(7) fetchUsers(8) fetchUsers(9)改善方法
リゾルバで即座にリクエストを送るのではなく、問い合わせたいIDを溜めて、バッチ処理で一つのリクエストに複数IDを載せて送ることでリクエストの量を削減させる。
※この場合、内部APIの方を複数IDに対応させる必要がある。DataLoaderとTypeGraphQL-DataLoaderを使うことでこれを簡単に実現できる。
DataLoader
は遅延読み込みをするためのFacebook製のライブラリで、TypeGraphQL-DataLoader
はDataLoaderをTypeGraphQLに適用させたライブラリである。組み込み方法
ライブラリをインストールする。
npm i -S dataloader type-graphql-dataloader
プラグインを読み込む。
const server = new ApolloServer({ schema: await makeSchema(), validationRules: [depthLimit(7)], plugins: [ // これを追加 ApolloServerLoaderPlugin({}), ] });
user
リゾルバをこのように修正する。@Resolver(of => Record) class RecordResolver { @FieldResolver() @Loader<number, User | undefined>(async (ids) => { const users = await fetchUsers([...ids]); return ids.map((id) => users.find((user) => user.userid === id)); }) user(@Root() record: Record) { return async (dataloader: DataLoader<number, User | undefined>) => { const user = await dataloader.load(record.userid); return user; }; } }10件取得するとこのようなログになる。
fetchUsers(0,1,2,3,4,5,6,7,8,9)おわりに
N+1問題は気づかずにDBや他のサーバーに負荷をかけてしまう可能性があるので注意して設計してほしい。
DataLoaderを使えば、意外と簡単に改善できるのでこれからも活用していきたい。
- 投稿日:2021-02-28T14:55:43+09:00
話題のesbuildをさっくりと調査してみた
今大注目のesbuildに関してさっくり調べて見ました。
ゆるめの記事です。調査のきっかけ
私がフロントを本格的に勉強し始めたのは2016-2017年のAngular2が出たころです。モダンフロントエンド開発の選択肢が増え、
PWAが提唱されるなどWEBフロントエンドが一気にリッチ化すると同時にカオス化した時期だったと思います。
つまり、本当に面白い状況だったのですが最近になってその状況も落ち着いてきたと感じている方も少なくないと思います。昔よくあった、React vs Angular vs Vue論争の熱は冷めたし、
SSRだけでペラペラだった(ドキュメントもダサかったw)Next.jsも2019~2020年の大規模機能拡張でフルスタックフレームワークとして堂々たるツールに成長し、今では画像配信サーバを内臓し、画像の最適化まで面倒をみてくれます。
この背景として、先立って機能拡充が進んでいたNuxt.jsからのいいとこ取りができたところも大きいと思います。私はAnguler, Nuxt, Nextを業務で使用したことがありますが、どのライブラリやフレームワークを使っても大体のことはできるし、
お互いを比較した時に、突出した優位性などはほとんどないと思っています。(個人的にreactが書いていて一番しっくりくるという好き嫌いくらいの話です。)この成熟したフロントエンド環境の最後の大課題といっていいのがコンパイラとバンドラのパフォーマンスといってもいいと思います!
2020年は上述の背景の中、SPA系のプロジェクトの注目度も依然高い状況ですが、新たにビルドツール系のstar数の急激な伸びが印象的です。ビルドツールのトレンドランキング!こちらをご参考
順位 名前 増加数 1 esbuild +16.6k 2 Rome +14.2k 3 Vita +14.1k 4 Snowpack +10.1k 5 Webpack +4.5k う〜ん、とはいえみなさん、ビルドツールってなんか地味な印象ありませんか?私はそうでした。
ビルドツールといえば、フロントオタクがwebpackをゴリゴリチューニングしたり、rollupなどの色々ツールがあるもいまいち根本的にビジネスメリットがあるわけでもないし、
下手に手を出すと技に溺れやすい世界だし(公式ドキュメントにシンプルに保ちなさい的なこと書いてあるよね!)、第一最適化はフレームワークに任せればいいじゃん!っと考えていました。しかし、今回注目したいesbuildはまさにフロントエンドの次の時代を作ってくれる様な、「すごい」ツールであるとキラキラとした期待を寄せてしまいます。
esbuildとは
webpackなどに変わるフロントエンドのコード変換+バンドルツールで、なんとWebpackと比較して10-100倍速度が早いそうです。
これが本当だとすると、フロントの開発効率は根本的に変わってくると思います。
当然の話ですが、現在のWebpackを使った各フレームワークのビルドはめちゃめちゃ遅いです。
nextやnuxtなどフレームワークで初期プロジェクトを構築し、デザインフレームワークを一つでも挿そうものなら、既に数十秒のビルド時間を覚悟する必要があります。
開発効率の向上のためのdev serverは、バンドルサイズが非常に重くブラウザのパフォーマンスが非常に厳しいものがあります。
また、HMRも実装が複雑らしくうまく反映されないことがあったり、SSRと相性が悪かったりと有効なシチュエーションが限られている現状です。
特に本番系でしか出ないエラーに遭遇した際は本当に泣くしかありませんw 数分(数十分)かけてビルドして、修正して、もう一回ビルドという経験をされている方も少なくないと思います。この様に中規模以上のフロントエンド開発経験者であれば、「ビルドの遅さ」との戦いは開発プロセスの根本的な課題であることが実感としてあり、解決可能であれば正にエポックメイキングで、夢の様な話だなぁと感じます。
(本当かなぁ?)esbuildの調査に当たってはアーキテクチャーなども見てみましたが、
the-super-tiny-compilerを読んだ程度では全く知識が足りずさっぱりでした、、w
そのせいか、開発は殆どEvan一人で進めている様です。ちなみに、esbuildは2021/01時点でスター数が19kなので、本当に彗星のごとく現れたということが分かります。
さらにランキング3vita
はesbuildに依存しています。vueはビルドプロセスが独特なので、esbuildとは別のレイヤーで対応するべきとVueのEvanとesbuildのEvanがgit上で議論しています。
(kabukuさんの記事 より。)
4位のSnowpcakもesbuildに依存しています。試してみた
create-next-appでプロジェクトを作成し、起動方法をreact-scriptからesbuildに変更してみました。
具体的にはプロジェクトのルートに下記のスクリプトを作成し、node build.js
を実行することでビルドします。build.jsconst watch = process.env.WATCH === 'true'; console.log( process.env.WATCH, watch ); require('esbuild').build({ entryPoints: ['src/index.tsx'], bundle: true, outfile: 'dist/out.js', define: { "process.env.NODE_ENV": '"development"' }, loader: { '.svg': 'dataurl' }, minify: false, sourcemap: true, target: ['chrome70', 'firefox57', 'safari11', 'edge16'], watch, }).catch(() => process.exit(1))webpackを使用したことがある方であれば、なかなかシンプルで分かりやすい設定だと思います。
これだけの設定でバンドルを生成してくれます。実際に実行してみました。
time node build.js > real 0m0.282sこれはっっ、本当に早い!
初期状態のプロジェクトでもdev-serverを立ち上げるまでに数秒は待たされる所なので、春の日差しの様な清々しさを感じます。esbuildできないこと
esbuildはまだ実験段階のプロダクトであるということと、パフォーマンスのため出来るだけシンプルな機能群に絞っているということもあり、出来ないこともはっきりしています。
私が確認した限りですと、下記はesbuildで実行することが出来ません。
- es5への変換
- CSS Modules
- Code Splitting と import() による lazy loading
- next.jsでの利用 ( next-babel-loaderの置き換えが難しい )
- ポストCSSの利用
- HMR
HMRに関しては対応の優先順は相当低そうです。(議論 => https://github.com/evanw/esbuild/issues/97)
こちらの議論によると、HMRはそもそもビルドが遅く、検証バンドルが重いWebpack環境ではデザインの編集など一部のユースケースで有効なこともありますが、
esbuildはそもそもビルドが爆速なので需要がそこまで高くないのと、HMRは複雑で実装コストが非常に高いということがあげられる様です。esbuildができること
差分ビルド
watch: true
をすることで差分ビルドを走らせることができます。無論超高速です。Base Pathの変更、Path Aliasの使用
TypeScriptを使用しているとベースパスの変更、パスエイリアスを使いたいことがあります。
// tsconfig.json { "baseUrl": "./src/", "paths": { "@/*": ["./*"] }, } // index.tsx import App from 'components/App'; // or import App from '@/components/App';これは、自動的にパスを解釈してくれる様です。webpackだと、resolve.aliasを調整しないといけなかったりするので便利ですね。
CSS import
よくプロジェクトのルートでcssをimportしたいことがあります。
index.tsimport App from 'assets/styles/global.css';この場合、index.tsxをバンドルすると、自動的にimportしているcssを全てまとめて、一つのcssファイルとして書き出してくれます。
今回のビルド設定だと、dist/out.css
が生成されます。デザインライブラリの利用
material-uiと、私が最近贔屓にしているantdを読み込んでみましたが普通に使えました。
antdはcssを別途読み込む必要があり、公式ページのgetting startedではcssファイル内にimportを記述する方法が記載されていますが、
うまく行かないので、index.tsxでimportしてあげる様にすると動きました。本当に早いのか
antdのボタンを一つ配置した状態でビルドをおこなってみました。
import { Button } from 'antd';まずはWebpack選手。下記の通りwebpcak.configを書いて実行しています。
計測には time とspeed-measure-webpack-plugin
を利用しました。webpack.config.jsconst path = require( 'path' ); const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); module.exports = smp.wrap({ mode: 'development', entry: path.resolve( __dirname, 'src/index.tsx' ), output: { path: path.resolve( __dirname, 'dist' ), filename: 'bundle.js' }, module: { rules: [ { test: /\.(jsx|tsx|ts|js)$/, exclude: /node_modules/, loader: 'ts-loader' }, { test: /\.(svg)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, }, }, ], }, { test: /\.css$/, loaders: ['style-loader', 'css-loader'], }, ] }, resolve: { extensions: ['.js', '.jsx', '.tsx', '.ts'], alias: { '@': path.resolve( __dirname, './src' ), }, modules: [ path.resolve( __dirname, './src' ), path.resolve( __dirname, './node_modules' ), ] }, plugins: [], });実行
time npx webpack --config webpack.config.js結果
SMP ⏱ General output time took 8.73 secs SMP ⏱ Loaders ts-loader took 5.24 secs module count = 4 modules with no loaders took 2.99 secs module count = 1030 css-loader took 0.449 secs module count = 3 url-loader took 0.066 secs module count = 1 style-loader, and css-loader took 0.037 secs module count = 3 real 0m10.665s10秒ちょっとなので、そんなもんかなぁという感じですね。
続いてesbuildです!
実行!
time node build.js
結果
real 0m0.608s再び、春の日差しの様な清々しさと額の辺りに微かな清涼感を感じました。
esbuildの方が約18倍高速ですさらに
esbuild-loader
なるものがあって、
webpcakのbabel-laoderやts-loaderを置き換える様にして使用することできます。esbuild-loaderではcss importの解決ができない様で、ビルドを通すことができなかったのですが途中までのログはこんな感じです。
SMP ⏱ General output time took 4.055 secs SMP ⏱ Plugins ESBuildPlugin took 0.01 secs SMP ⏱ Loaders esbuild-loader took 3.67 secs module count = 1033 modules with no loaders took 0.019 secs module count = 3むむ?esbuild-loaderの所で3.6秒も使ってますね。実際にesbuild-loaderのissueをみても、
倍程度にしか高速化していないので、こんなものなのかもしれません。(それでも最高ではありますが。)まとめるとこんな結果になりました。
ビルド方法 時間(約) ファイルサイズ Webpack(dev) 10.6秒 6.92Mb Webpcak(prd) 18.2秒 2.16Mb esbuild(dev) 0.6秒 1.1Mb + 710kb esbuild(prd) 0.6秒 420kb + 720kb esbuildの場合、jsとcssは別バンドルになるので、ファイルサイズはjs, cssの順で記載しています。
これを見ると、本番ビルドではなんと30倍も高速であることが分かります!またファイルサイズもいずれもWebpackより小さくなっている様で、
開発時のブラウザの負荷も段違いだと思います。実践投入に関して
まだesbuildは実験段階に位置付けられていますが、vita, snowpackなどすでに多くの新興ツールが依存している状態になり、今後の発展は非常に期待ができると思われます。
しかしながら、やっぱり本番運用まだ怖い場合は、ABEMAさんの記事でも提案されている様に、
検証系のビルド方法に一手間加えて、DXの爆上げという目的が使いやすいと思います。将来的にエビデンスなどが揃いstableなツールとなれば、超高速CI/CDの実現など夢は広がります。
まとめ
esbuildはやっぱり早かった!SPAページを作成する際はあえて、nextを断念してでも導入を検討したいと思いました。
また、DenoやRomeなどのエコシステムのネクストジェネレーション?的なツールがどんどん出てきていますので、
近いうちに調査、比較を行ってみたいと思います。長文になりましたが、最後まで読んでくださった方は、ありがとうございました。
- 投稿日:2021-02-28T14:55:43+09:00
さっくりとesbuildを調査してみた
今大注目のesbuildに関してさっくり調べて見ました。
ゆるめの記事です。調査のきっかけ
私がフロントを本格的に勉強し始めたのは2016-2017年のAngular2が出たころです。モダンフロントエンド開発の選択肢が増え、
PWAが提唱されるなどWEBフロントエンドが一気にリッチ化すると同時にカオス化した時期だったと思います。
つまり、本当に面白い状況だったのですが最近になってその状況も落ち着いてきたと感じている方も少なくないと思います。昔よくあった、React vs Angular vs Vue論争の熱は冷めたし、
SSRだけでペラペラだった(ドキュメントもダサかったw)Next.jsも2019~2020年の大規模機能拡張でフルスタックフレームワークとして堂々たるツールに成長し、今では画像配信サーバを内臓し、画像の最適化まで面倒をみてくれます。
この背景として、先立って機能拡充が進んでいたNuxt.jsからのいいとこ取りができたところも大きいと思います。私はAnguler, Nuxt, Nextを業務で使用したことがありますが、どのライブラリやフレームワークを使っても大体のことはできるし、
お互いを比較した時に、突出した優位性などはほとんどないと思っています。(個人的にreactが書いていて一番しっくりくるという好き嫌いくらいの話です。)この成熟したフロントエンド環境の最後の大課題といっていいのがコンパイラとバンドラのパフォーマンスといってもいいと思います!
2020年は上述の背景の中、SPA系のプロジェクトの注目度も依然高い状況ですが、新たにビルドツール系のstar数の急激な伸びが印象的です。ビルドツールのトレンドランキング!こちらをご参考
順位 名前 増加数 1 esbuild +16.6k 2 Rome +14.2k 3 Vita +14.1k 4 Snowpack +10.1k 5 Webpack +4.5k う〜ん、とはいえみなさん、ビルドツールってなんか地味な印象ありませんか?私はそうでした。
ビルドツールといえば、フロントオタクがwebpackをゴリゴリチューニングしたり、rollupなどの色々ツールがあるもいまいち根本的にビジネスメリットがあるわけでもないし、
下手に手を出すと技に溺れやすい世界だし(公式ドキュメントにシンプルに保ちなさい的なこと書いてあるよね!)、第一最適化はフレームワークに任せればいいじゃん!っと考えていました。しかし、今回注目したいesbuildはまさにフロントエンドの次の時代を作ってくれる様な、「すごい」ツールであるとキラキラとした期待を寄せてしまいます。
esbuildとは
webpackなどに変わるフロントエンドのコード変換+バンドルツールで、なんとWebpackと比較して10-100倍速度が早いそうです。
これが本当だとすると、フロントの開発効率は根本的に変わってくると思います。
当然の話ですが、現在のWebpackを使った各フレームワークのビルドはめちゃめちゃ遅いです。
nextやnuxtなどフレームワークで初期プロジェクトを構築し、デザインフレームワークを一つでも挿そうものなら、既に数十秒のビルド時間を覚悟する必要があります。
開発効率の向上のためのdev serverは、バンドルサイズが非常に重くブラウザのパフォーマンスが非常に厳しいものがあります。
また、HMRも実装が複雑らしくうまく反映されないことがあったり、SSRと相性が悪かったりと有効なシチュエーションが限られている現状です。
特に本番系でしか出ないエラーに遭遇した際は本当に泣くしかありませんw 数分(数十分)かけてビルドして、修正して、もう一回ビルドという経験をされている方も少なくないと思います。この様に中規模以上のフロントエンド開発経験者であれば、「ビルドの遅さ」との戦いは開発プロセスの根本的な課題であることが実感としてあり、解決可能であれば正にエポックメイキングで、夢の様な話だなぁと感じます。
(本当かなぁ?)esbuildの調査に当たってはアーキテクチャーなども見てみましたが、
the-super-tiny-compilerを読んだ程度では全く知識が足りずさっぱりでした、、w
そのせいか、開発は殆どEvan一人で進めている様です。ちなみに、esbuildは2021/01時点でスター数が19kなので、本当に彗星のごとく現れたということが分かります。
さらにランキング3vita
はesbuildに依存しています。vueはビルドプロセスが独特なので、esbuildとは別のレイヤーで対応するべきとVueのEvanとesbuildのEvanがgit上で議論しています。
(kabukuさんの記事 より。)
4位のSnowpcakもesbuildに依存しています。試してみた
create-next-appでプロジェクトを作成し、起動方法をreact-scriptからesbuildに変更してみました。
具体的にはプロジェクトのルートに下記のスクリプトを作成し、node build.js
を実行することでビルドします。build.jsconst watch = process.env.WATCH === 'true'; console.log( process.env.WATCH, watch ); require('esbuild').build({ entryPoints: ['src/index.tsx'], bundle: true, outfile: 'dist/out.js', define: { "process.env.NODE_ENV": '"development"' }, loader: { '.svg': 'dataurl' }, minify: false, sourcemap: true, target: ['chrome70', 'firefox57', 'safari11', 'edge16'], watch, }).catch(() => process.exit(1))webpackを使用したことがある方であれば、なかなかシンプルで分かりやすい設定だと思います。
これだけの設定でバンドルを生成してくれます。実際に実行してみました。
time node build.js > real 0m0.282sこれはっっ、本当に早い!
初期状態のプロジェクトでもdev-serverを立ち上げるまでに数秒は待たされる所なので、春の日差しの様な清々しさを感じます。esbuildできないこと
esbuildはまだ実験段階のプロダクトであるということと、パフォーマンスのため出来るだけシンプルな機能群に絞っているということもあり、出来ないこともはっきりしています。
私が確認した限りですと、下記はesbuildで実行することが出来ません。
- es5への変換
- CSS Modules
- Code Splitting と import() による lazy loading
- next.jsでの利用 ( next-babel-loaderの置き換えが難しい )
- ポストCSSの利用
- HMR
HMRに関しては対応の優先順は相当低そうです。(議論 => https://github.com/evanw/esbuild/issues/97)
こちらの議論によると、HMRはそもそもビルドが遅く、検証バンドルが重いWebpack環境ではデザインの編集など一部のユースケースで有効なこともありますが、
esbuildはそもそもビルドが爆速なので需要がそこまで高くないのと、HMRは複雑で実装コストが非常に高いということがあげられる様です。esbuildができること
差分ビルド
watch: true
をすることで差分ビルドを走らせることができます。無論超高速です。Base Pathの変更、Path Aliasの使用
TypeScriptを使用しているとベースパスの変更、パスエイリアスを使いたいことがあります。
// tsconfig.json { "baseUrl": "./src/", "paths": { "@/*": ["./*"] }, } // index.tsx import App from 'components/App'; // or import App from '@/components/App';これは、自動的にパスを解釈してくれる様です。webpackだと、resolve.aliasを調整しないといけなかったりするので便利ですね。
CSS import
よくプロジェクトのルートでcssをimportしたいことがあります。
index.tsimport App from 'assets/styles/global.css';この場合、index.tsxをバンドルすると、自動的にimportしているcssを全てまとめて、一つのcssファイルとして書き出してくれます。
今回のビルド設定だと、dist/out.css
が生成されます。デザインライブラリの利用
material-uiと、私が最近贔屓にしているantdを読み込んでみましたが普通に使えました。
antdはcssを別途読み込む必要があり、公式ページのgetting startedではcssファイル内にimportを記述する方法が記載されていますが、
うまく行かないので、index.tsxでimportしてあげる様にすると動きました。本当に早いのか
antdのボタンを一つ配置した状態でビルドをおこなってみました。
import { Button } from 'antd';まずはWebpack選手。下記の通りwebpcak.configを書いて実行しています。
計測には time とspeed-measure-webpack-plugin
を利用しました。webpack.config.jsconst path = require( 'path' ); const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); module.exports = smp.wrap({ mode: 'development', entry: path.resolve( __dirname, 'src/index.tsx' ), output: { path: path.resolve( __dirname, 'dist' ), filename: 'bundle.js' }, module: { rules: [ { test: /\.(jsx|tsx|ts|js)$/, exclude: /node_modules/, loader: 'ts-loader' }, { test: /\.(svg)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, }, }, ], }, { test: /\.css$/, loaders: ['style-loader', 'css-loader'], }, ] }, resolve: { extensions: ['.js', '.jsx', '.tsx', '.ts'], alias: { '@': path.resolve( __dirname, './src' ), }, modules: [ path.resolve( __dirname, './src' ), path.resolve( __dirname, './node_modules' ), ] }, plugins: [], });実行
time npx webpack --config webpack.config.js結果
SMP ⏱ General output time took 8.73 secs SMP ⏱ Loaders ts-loader took 5.24 secs module count = 4 modules with no loaders took 2.99 secs module count = 1030 css-loader took 0.449 secs module count = 3 url-loader took 0.066 secs module count = 1 style-loader, and css-loader took 0.037 secs module count = 3 real 0m10.665s10秒ちょっとなので、そんなもんかなぁという感じですね。
続いてesbuildです!
実行!
time node build.js
結果
real 0m0.608s再び、春の日差しの様な清々しさと額の辺りに微かな清涼感を感じました。
esbuildの方が約18倍高速ですさらに
esbuild-loader
なるものがあって、
webpcakのbabel-laoderやts-loaderを置き換える様にして使用することできます。esbuild-loaderではcss importの解決ができない様で、ビルドを通すことができなかったのですが途中までのログはこんな感じです。
SMP ⏱ General output time took 4.055 secs SMP ⏱ Plugins ESBuildPlugin took 0.01 secs SMP ⏱ Loaders esbuild-loader took 3.67 secs module count = 1033 modules with no loaders took 0.019 secs module count = 3むむ?esbuild-loaderの所で3.6秒も使ってますね。実際にesbuild-loaderのissueをみても、
倍程度にしか高速化していないので、こんなものなのかもしれません。(それでも最高ではありますが。)まとめるとこんな結果になりました。
ビルド方法 時間(約) ファイルサイズ Webpack(dev) 10.6秒 6.92Mb Webpcak(prd) 18.2秒 2.16Mb esbuild(dev) 0.6秒 1.1Mb + 710kb esbuild(prd) 0.6秒 420kb + 720kb esbuildの場合、jsとcssは別バンドルになるので、ファイルサイズはjs, cssの順で記載しています。
これを見ると、本番ビルドではなんと30倍も高速であることが分かります!またファイルサイズもいずれもWebpackより小さくなっている様で、
開発時のブラウザの負荷も段違いだと思います。実践投入に関して
まだesbuildは実験段階に位置付けられていますが、vita, snowpackなどすでに多くの新興ツールが依存している状態になり、今後の発展は非常に期待ができると思われます。
しかしながら、やっぱり本番運用まだ怖い場合は、ABEMAさんの記事でも提案されている様に、
検証系のビルド方法に一手間加えて、DXの爆上げという目的が使いやすいと思います。将来的にエビデンスなどが揃いstableなツールとなれば、超高速CI/CDの実現など夢は広がります。
まとめ
esbuildはやっぱり早かった!SPAページを作成する際はあえて、nextを断念してでも導入を検討したいと思いました。
また、DenoやRomeなどのエコシステムのネクストジェネレーション?的なツールがどんどん出てきていますので、
近いうちに調査、比較を行ってみたいと思います。長文になりましたが、最後まで読んでくださった方は、ありがとうございました。
- 投稿日:2021-02-28T09:56:50+09:00
【Node.js】promiseの使い方
プログラミング勉強日記
2021年2月28日
基本的な書き方
promise処理を作るには任意の関数の中で
new Promise()
を返すのが基本となる。return new Promise(resolve) { // 処理を記述する }具体例function myFunction() { return new Promise(function (resolve) { resolve("Hello World"); }) }thenを使ったメソッドチェーン
promiseによる非同期処理の結果を取得するにはthenを使ったメソッドチェーンを使用することができる。
// dataにpromiseの結果が格納されている // resolve()に設定した文字列になる myFunction().then(function(data) { console.log(data) })実行結果Hello Worldpromiseの並列処理
allメソッドとraceメソッドを使った方法がある。
allメソッドは、違うpromise処理が記述された関数をまとめて実行して、すべての結果が得られたタイミングでthenを実行できるようにする。なので、複数のpromise処理の結果をまとめて取得したい場合に向いてる。
raceメソッドも複数のpromise処理を実行できるが、最初に結果が得られたpromiseの結果だけをthenメソッドで取得できる。エラーハンドリング
promiseの引数には結果を格納するresolveだけではなく、エラー情報を格納するrejectを利用できる。
function myFunction() { return new Promise(function (resolve, reject) { reject(new Error("エラーが発生しました")); }) }myPromise() .then(function(data) { console.log(data); }, function(error) { console.log(error.message); })実行結果エラーが発生しました参考文献
非同期処理:コールバック/Promise/Async Function
【node.js入門】Promiseによる非同期処理の使い方まとめ!
- 投稿日:2021-02-28T03:38:35+09:00
Node.js版CCXTでbitFlyerのPrivate APIを使う
はじめに
ccxt.js経由でbitFlyerの現在のポジション(建玉)を知りたかったのだが、ちょっと調べてもなかった。
詰まったので同様の問題に遭遇した人のためにも解決方法残しておこうと思う。コード
const ccxt = require('ccxt') const bitflyer = new ccxt.bitflyer({ apiKey: env.apiKey, // APIキーを入れる secret: env.secret // シークレットをいれる }) bitflyer.privateGetGetpositions({ product_code: 'FX_BTC_JPY' }).then(data => console.log(data))ちょっと解説
ccxtでPrivate APIを使うには、メソッドの命名に独自の法則を使っている
private + {メソッドがgetならGet、postならPost} + {private APIの名前}上の例ではGetメソッドで
getpositions
APIを使いたいがために、privateGetGetpositions
となる。
またクエリパラメータが必須なので、それはメソッドの引数としてオブジェクトを渡す。参考
Python版だが以下の説明がわかりやすかった。
Bitflyerや各取引所の個別APIをCCXTライブラリ経由で直接利用する方法使いたいbitFlyerのPrivate APIは以下を参照
API Documentation
- 投稿日:2021-02-28T00:38:57+09:00
[Node.js][LINE] 毎朝 LINE に花粉情報を通知する
概要
に引き続き、LINE Notify を使って LINE に通知するシリーズです!
花粉 が辛い季節ですね 花粉情報が非常に気になる毎日なので、毎朝当日の花粉情報を LINE に通知するようにしました。
方法
バージョン情報
- Node.js 14.15.5
- Playwright 1.9.1
- axios 0.21.1
コード
まず Playwright を使ってヘッドレス Chrome を操作し、Yahoo! JAPAN の花粉情報のスクリーンショットを撮影します。花粉情報のページの URL は任意の地域のものに書き換えてください。本当は 日本気象協会 tenki.jp の花粉情報を通知したかったのですが、Playwright でのアクセスがタイムアウトになってしまうので諦めました (スクレイピング対策されているのかも) 。
そして axios を使って LINE Notify の API を叩き、LINE に通知します。LINE Notify はメッセージを送信できるだけでなく、画像を送信することもできます。
~/workspace/death_powder_forcast/main.jsconst { chromium } = require('playwright'); const fs = require('fs'); const axios = require('axios'); const FormData = require('form-data'); // Yahoo! JAPAN の福岡市中央区の花粉情報。 const POLLEN_FORCAST_URL = 'https://weather.yahoo.co.jp/weather/pollen/10/40/40133/'; const SCREENSHOT_FILEPATH = './today.png'; const LINE_NOTIFY_TOKEN = 'ここに LINE Notify のトークンを入力する。'; // 指定した要素のスクリーンショットを撮影する。 const takeScreenshot = async ({ url, selector, filepath }) => { // Raspberry Pi では ARM 用の Chromium を使用する必要があるので executablePath を指定する。 const browser = await chromium.launch({ executablePath: '/usr/bin/chromium-browser' }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto(url); const element = await page.$(selector); await element.screenshot({ path: filepath }) await browser.close(); }; // LINE Notify に通知する。 const notifyLINE = async ({ token, message, imageFilepath = null }) => { const LINE_NOTIFY_API_URL = 'https://notify-api.line.me/api/notify'; const formData = new FormData(); formData.append('message', message); if (imageFilepath) { formData.append('imageFile', fs.createReadStream(SCREENSHOT_FILEPATH)); } const headers = { 'Authorization': `Bearer ${token}`, ...formData.getHeaders() }; await axios.post(LINE_NOTIFY_API_URL, formData, { headers }); }; (async () => { await takeScreenshot({ url: POLLEN_FORCAST_URL, selector: '.pollenFlying_city_day:first-child', filepath: SCREENSHOT_FILEPATH }); if (!fs.existsSync(SCREENSHOT_FILEPATH)) { process.exit(1); } await notifyLINE({ token: LINE_NOTIFY_TOKEN, message: '今日の花粉情報です。', imageFilepath: SCREENSHOT_FILEPATH }) fs.unlinkSync(SCREENSHOT_FILEPATH); })();上記の Node.js ファイルを cron で定期実行します。時刻はリマインドしてほしい時刻を指定してください。
crontab# 設定例 0 7 * * * /bin/bash -c 'export PATH=$HOME/.nodenv/bin:$PATH; eval "$(nodenv init -)"; cd $HOME/workspace/death_powder_forcast; node main.js'これで通知が届きました ?
- 投稿日:2021-02-28T00:38:57+09:00
[Node.js][LINE] 毎日 LINE に花粉情報を通知する
概要
に引き続き、LINE Notify を使って LINE に通知するシリーズです!
花粉 が辛い季節ですね 花粉情報が非常に気になる毎日なので、当日の花粉情報を LINE に通知するようにしました。
方法
バージョン情報
- Node.js 14.15.5
- Playwright 1.9.1
- axios 0.21.1
コード
まず Playwright を使ってヘッドレス Chrome を操作し、Yahoo! JAPAN の花粉情報のスクリーンショットを撮影します。花粉情報のページの URL は任意の地域のものに書き換えてください。なお、本当は 日本気象協会 tenki.jp の花粉情報を通知したかったのですが、Playwright でのアクセスがタイムアウトになってしまうので諦めました。スクレイピング対策されているのかもしれませんね。
そして axios を使って LINE Notify の API を叩き、LINE に通知します。LINE Notify はメッセージを送信できるだけでなく、画像を送信することもできます。
~/workspace/death_powder_forcast/main.jsconst { chromium } = require('playwright'); const fs = require('fs'); const axios = require('axios'); const FormData = require('form-data'); // Yahoo! JAPAN の福岡市中央区の花粉情報。 const POLLEN_FORCAST_URL = 'https://weather.yahoo.co.jp/weather/pollen/10/40/40133/'; const SCREENSHOT_FILEPATH = './today.png'; const LINE_NOTIFY_TOKEN = 'ここに LINE Notify のトークンを入力する。'; // 指定した要素のスクリーンショットを撮影する。 const takeScreenshot = async ({ url, selector, filepath }) => { // Raspberry Pi では ARM 用の Chromium を使用する必要があるので executablePath を指定する。 const browser = await chromium.launch({ executablePath: '/usr/bin/chromium-browser' }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto(url); const element = await page.$(selector); await element.screenshot({ path: filepath }); await browser.close(); }; // LINE Notify に通知する。 const notifyLINE = async ({ token, message, imageFilepath = null }) => { const LINE_NOTIFY_API_URL = 'https://notify-api.line.me/api/notify'; const formData = new FormData(); formData.append('message', message); if (imageFilepath) { formData.append('imageFile', fs.createReadStream(imageFilepath)); } const headers = { 'Authorization': `Bearer ${token}`, ...formData.getHeaders() }; await axios.post(LINE_NOTIFY_API_URL, formData, { headers }); }; (async () => { await takeScreenshot({ url: POLLEN_FORCAST_URL, selector: '.pollenFlying_city_day:first-child', filepath: SCREENSHOT_FILEPATH }); if (!fs.existsSync(SCREENSHOT_FILEPATH)) { process.exit(1); } await notifyLINE({ token: LINE_NOTIFY_TOKEN, message: '今日の花粉情報です。', imageFilepath: SCREENSHOT_FILEPATH }); fs.unlinkSync(SCREENSHOT_FILEPATH); })();上記の Node.js ファイルを cron で定期実行します。通知してほしい時刻を指定してください。
crontab# 設定例 0 7 * * * /bin/bash -c 'export PATH=$HOME/.nodenv/bin:$PATH; eval "$(nodenv init -)"; cd $HOME/workspace/death_powder_forcast; node main.js'これで通知が届きました ?
- 投稿日:2021-02-28T00:13:52+09:00
nodebrewを利用したnodeのインストール
Homebrewを使ってインストール。
$ brew install nodebrew
- バージョン確認
$ nodebrew -v
- セットアップコマンド。出力されたパスを通す。
$ nodebrew setup # Fetching nodebrew... # Installed nodebrew in $HOME/.nodebrew # # ======================================== # Export a path to nodebrew: # # export PATH=$HOME/.nodebrew/current/bin:$PATH <= コイツを記述 # ========================================$ vi ~/.bash_profile
- インストール可能なバージョンの確認
$ nodebrew ls-remote
- stableをインストール。
install
コマンドと比較してinstall-binary
の方が速いらしい。$ nodebrew install-binary stable
- インストールしたバージョンの確認。及び実行するバージョンを指定。
$ nodebrew ls # v14.16.0 # # current: none$ nodebrew use v14.16.0
- バージョンの確認。
$ nodebrew ls # v14.16.0 # # current: v14.16.0$ node -v以上