webpack(ウェブパック)は、複数のJSファイルをまとめてくれるツールです。
webpackは「gulp」「Grunt 」「Browserify」のようなタスクランナーですが、最大の特徴は「モジュールバンドラ」です。
モジュールバンドラーはファイルをまとめることを指し、複数のモジュール(ここではJS)の依存関係を解決します。
今回は下記を参考にて webpack4 を npm で構築してみました。
最新版で学ぶwebpack 4入門 JavaScriptのモジュールバンドラ
webpackのメリットはいくつかあります。
など、今まで別々で管理していたJSファイルを1つにまとめることで、フロントエンド開発手法そのものが変わってきます。
gulp で開発してきた場合は、gulp + webpack で運用してるようですが、新規ならば webpack で十分みたいです(開発者の好みか?)。
node.js のバージョンは13以上
$ node -v
v13.6.0
webpack のテストサンプルを利用するロジェクトを作成する。
また、npm init で package.json も作成しておく。
$ mkdir webpack-test
$ cd webpack-test
$ npm init -y
$ mkdir src
devDependencies(-D) で webpack webpack-cli をインストールする
$npm i -D webpack webpack-cli
...
+ webpack-cli@3.3.11
+ webpack@4.41.6
...
現時点で、「モジュール方式」で JavaScript を実装することが推奨されている。
※ECMAScript Modules(ES Modules、ESM)
webpack4 では明示的に指定しない場合、以下の設定となります。
import { say } from "./module1";
say();
export function say() {
alert("module1 hello!");
}
手っ取り早く npm 5.2.0 で追加された「npx」コマンドで webpack ビルドしてみる。
(npm run build で webpack を動作させた方が応用が効くが)
$ npx webpack
Hash: 58e8f21bff04a84f6d5c
Version: webpack 4.41.6
Time: 247ms
Built at: 2020/02/27 20:49:44
Asset Size Chunks Chunk Names
main.js 957 bytes 0 [emitted] main
Entrypoint main = main.js
[0] ./src/index.js + 1 modules 96 bytes {0} [built]
| ./src/index.js 42 bytes [built]
| ./src/person.js 54 bytes [built]
src/index.js に src/person.js が統合され dist/main.js が書き出される
index.html を作成し「dist/main.js」を読み込む
npx webpack でなく package.json を設定して npm ビルドする
{
"name": "webpack-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11"
},
"devDependencies": {
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11"
},
"scripts": {
"build": "webpack"
}
}
npm run build で webpack ビルドされる
$ npm run build
> webpack-test@1.0.0 build /Users/yoo/docker/projects/webpack-test
> webpack
...
webpack.config.js を作成して、「entry」「output」を設定することで、エントリポイント、出力先ファイルをカスタマイズできます。
※前述の通り webpack4 では「src/index.js」「dist/main.js」がデフォルト
module.exports = {
entry: `./src/index.js`,
output: {
path: `${__dirname}/dist`,
filename: "main.js"
},
mode: "development"
};
$ npm run build
modeを「development」にすると、出力ファイル(main.js)が圧縮されずに書き出されます。
webpack-dev-server をして、JavaScriptの実装をリアルタイムにブラウザ確認することもできるが、一般的なウォッチを利用してビルドする。
"scripts": {
"build": "webpack",
"watch": "webpack --watch"
},
$ npm run watch
これで、JavaScript を保存すると自動でビルドされます。
MacBook Pro 256 で開発やクリエイティブ作業していくと容量が厳しくなってきた。
自分の場合
がかなり容量を圧迫しています。
$ sudo du -gxd 5 / | awk '$1 >= 5{print}'
$ sudo du -gxd 1| awk '$1 >= 1{print}'
これらをもとに、手動で削除
Xcodeの場合、ツールコマンドを利用する
$ xcrun simctl list devices
== Devices ==
-- iOS 13.3
-- iPhone 8 (69D4A89A-704C-43E0-8C71-6437C551DEB6) (Shutdown) iPhone 11 (DC5B21DE-21CA-4624-8C1C-7CDC349B9DDA) (Shutdown) ...
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-10-1
-- iPhone 5 (CE4E79DC-CE71-47A9-B2C8-5F77EE73196F) (Shutdown) (unavailable, runtime profile not found) iPhone 5s (C94451DC-A342-46AE-8E69-52D6DF928E77) (Shutdown) (unavailable, runtime profile not found)
$ xcrun simctl delete unavailable
Dockerは不要なコンテナー、イメージが溜まりがち
$ docker image ls
$ docker images -f dangling=true
$ docker image rm $(docker image ls --filter "dangling=true" -aq)
$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 85 0 18.97GB 18.97GB (100%) Containers 0 0 0B 0B Local Volumes 24 0 80.44MB 80.44MB (100%) Build Cache 0 0 0B 0B
$ docker system prune
$ docker system prune -a
別途DAWを入れているので、Garageband は削除
$ sudo rm -rf /Applications/GarageBand.app
$ sudo rm -rf /Library/Application\ Support/GarageBand
$ sudo rm -rf /Library/Application\ Support/Logic
$ sudo rm -rf /Library/Audio/Apple\ Loops
$ sudo rm -rf /Library/Audio/Apple\ Loops\ Index
DIについては、DI(依存性注入) を参照
DIコンテナは、DIのインスタンス生成を、別のファイルでコンテナ化して解決しようという設計パターンです。
まず、共通で使う Animalクラスを用意します。
手っ取り早くファイル分割せず Animal.php にクラス(Dog、Cat)を記述しました。
interface Animal {
public function bow();
}
class Dog implements Animal {
public function bow() {
echo 'wan! wan!'.PHP_EOL;
}
}
class Cat implements Animal {
public function bow() {
echo 'nya-! nya-!'.PHP_EOL;
}
}
下記のサンプルはコンストラクタ内で Dog を生成して鳴きます。
class AnimalConsole {
protected $dog;
public function __construct() {
$this->dog = new Dog();
}
public function bow() {
$this->dog->bow();
}
}
$animal_console = new AnimalConsole();
$animal_console->bow();
この場合、コンストラクタで new Dog() するため、Dogが実装できるまで AnimalConsole が実装できません。
コンストラクタの引数に、Dog、Cat インスタンスを注入します(コンストラクタインジェクション)
他の記事をみているとこれで「DI」となってますが、まだ Dog に依存しているため Cat に修正したい場合に手間がかかります。
require_once 'Animal.php';
class AnimalConsole {
protected $dog;
public function __construct(Dog $dog) {
$this->dog = $dog;
}
public function bow() {
$this->dog->bow();
}
}
$animal_console = new AnimalConsole(new Dog());
$animal_console->bow();
今度は Dog、Cat 両方扱えるように Amimal を引数とします。
require_once 'Animal.php';
class AnimalConsole {
protected $animal;
public function __construct(Amimal $animal) {
$this->animal = $animal;
}
public function bow() {
$this->animal->bow();
}
}
$animal_console1 = new AnimalConsole(new Dog());
$animal_console1->bow();
$animal_console2 = new AnimalConsole(new Cat());
$animal_console2->bow();
これで、Dog、Cat どちらでも注入できるようになりました。
インスタンスを直接渡すのではなく、コンテナ(箱)内でインスタンスを作成して処理するのが、DIコンテナです。
今回は、composerのContainerライブラリ「pimple」を利用しています。
$ composer require pimple/pimple ~3.0
下記の場合、Dog、Cat のインスタンスをコンテナ化しています。
また、$container['animal'] では、インスタンスを簡単に切り替えることができます。
require_once 'Animal.php';
require_once __DIR__.'/../vendor/autoload.php';
use Pimple\Container;
class AnimalConsole {
protected $animal;
public function __construct(
Animal $animal
) {
$this->animal = $animal;
}
public function bow() {
$this->animal->bow();
}
}
$container = new Container();
$container['dog'] = function($c) {
return new Dog();
};
$container['cat'] = function($c) {
return new Cat();
};
$container['animal'] = function($c) {
return $c['dog'];
};
$container['animalConsole'] = function ($c) {
return new AnimalConsole($c['animal']);
};
$container['animalConsole']->bow();
Container の部分はファイル分離する必要はあります。
ありそうでなかった会計向けSDK
freee が国内初なようで、2020/02時点の対応言語は「C#」「Java」「PHP」
freee API と統制をとるために「OpenApi generator」を利用して有志が開発しているとのこと
https://github.com/freee/freee-accounting-sdk-csharp/
https://github.com/freee/freee-accounting-sdk-java
https://github.com/freee/freee-accounting-sdk-php/
PHPの場合は、composer で用意されており、さらにサンプル用に Docker & Laravel が公開されている。
コールバックURL
freee APIアプリの「コールバックURL」は以下を設定しておく
※デフォルト:urn:ietf:wg:oauth:2.0:oob
※Laravel dでも後に設定する
http://localhost:8000/auth-callback
サンプルは SDK の中に入っているので git clone
$ git clone https://github.com/freee/freee-accounting-sdk-php.git
.env を設定する
$ cd freee-accounting-sdk-php.git
$ cd samples/BasicWebApp
$ cp .env.example .env
freeeアプリ の Client ID、Secret ID を記述
FREEE_ACCOUNTING_CLIENT_ID=Client ID
FREEE_ACCOUNTING_CLIENT_SECRET=Secret ID
freee-accounting-sdk-php にあるサンプルを利用する
$ cd freee-accounting-sdk-php/samples/BasicWebApp
$ cd samples
$ docker-compose build
$ docker-compose up -d
$ docker exec -it samples_webapp_1 /bin/bash
version: "3.7"
services:
console:
build:
context: .
dockerfile: Dockerfile
image: freee-accounting-sdk-php-console
volumes:
- "./BasicConsole:/usr/src/app"
command: /bin/sh -c "while sleep 1000; do :; done"
webapp:
build:
context: .
dockerfile: Dockerfile
image: freee-accounting-sdk-php-webapp
ports:
- "80:80"
- "8000:8000"
volumes:
- "./BasicWebApp:/usr/src/app"
command: /bin/sh -c "while sleep 1000; do :; done"
FROM php:7.3-cli
RUN apt-get update; \
curl -sL https://deb.nodesource.com/setup_12.x | bash -; \
apt-get install -y --no-install-recommends \
git \
libzip-dev \
nodejs \
unzip \
zlib1g-dev \
; \
rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install zip
WORKDIR /tmp
RUN curl https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -o - -s | php -- --quiet; \
mv composer.phar /usr/local/bin/composer
WORKDIR /usr/src/app
RUN composer global require laravel/installer
ENV PATH /root/.composer/vendor/bin:$PATH
EXPOSE 8000
webpackが用意されているので、すぐインストールできる
# composer install
composer、Laravel を直にインストールする場合
$ composer require freee/freee-accounting-sdk
$ composer require socialiteproviders/generators
$ composer require socialiteproviders/manager
artisan で socialiteproviders/generators を実行
$ php artisan make:socialite FreeeAccounting --spec=oauth2 --authorize_url=https://accounts.secure.freee.co.jp/public_api/authorize --access_token_url=https://accounts.secure.freee.co.jp/public_api/token --user_details_url=https://api.freee.co.jp/api/1/users/me
$ composer dumpautoload
Laravel/UI を作成
$ composer require laravel/ui --dev
$ php artisan ui vue --auth
$ npm install && npm run dev
# php artisan key:generate
# php artisan serve
Docker の場合は、ホスト指定します。
# php artisan serve --host 0.0.0.0
プロジェクトルートは「samples/BasicWebApp/」
Auth::routes([
'register' => false,
'reset' => false,
]);
Route::get('login', 'Auth\LoginController@redirectToProvider')->name('login');
Route::get('auth-callback', 'Auth\LoginController@handleProviderCallback')->name('authCallback');
「client_id」「client_secret」「redirect」をそれぞれ設定 (リダイレクトURLは、freeeのアプリ管理と合わせる)
'freeeaccounting' => [
'client_id' => env('FREEE_ACCOUNTING_CLIENT_ID'),
'client_secret' => env('FREEE_ACCOUNTING_CLIENT_SECRET'),
'redirect' => 'http://localhost:8000/auth-callback',
],
freee用ドライバー、プロバイダー設定
'defaults' => [
'guard' => 'freee',
'passwords' => 'users',
],
....
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'freee' => [
'driver' => 'freee',
'provider' => 'freee',
],
],
...
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'freee' => [
'driver' => 'freee',
],
],
ログイン処理は、Laravel Socialite ドライバーを利用し、GenericUser で認証する
use App\Http\Controllers\Controller;
use Illuminate\Auth\GenericUser;
use Illuminate\Support\Facades\Auth;
use Socialite;
...
public function redirectToProvider()
{
return Socialite::driver('freeeaccounting')->redirect();
}
public function handleProviderCallback()
{
$user = Socialite::driver('freeeaccounting')->user();
$genericUser = $user->getRaw();
$genericUser['token'] = $user->token;
$genericUser['remember_token'] = '';
Auth::login(new GenericUser($genericUser));
return redirect()->intended($this->redirectTo);
}
public function logout()
{
Auth::logout();
return redirect()->intended('/');
}
namespace App\Providers;
use App\Extensions\SampleSessionGuard;
use App\Extensions\FreeeUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
Auth::extend('freee', function ($app, $name, array $config) {
return new SampleSessionGuard(
$name,
Auth::createUserProvider($config['provider']),
$app['session.store']
);
});
Auth::provider('freee', function ($app, array $config) {
return new FreeeUserProvider();
});
}
}
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\FreeeAccounting\FreeeAccountingExtendSocialite;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
SocialiteWasCalled::class => [
FreeeAccountingExtendSocialite::class,
],
];
public function boot()
{
parent::boot();
}
}
https://api.freee.co.jp/api/1/users/me からユーザを返す関数を作成
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get('https://api.freee.co.jp/api/1/users/me', [
'headers' => [
'Authorization' => 'Bearer '.$token,
],
]);
$body = json_decode($response->getBody(), true);
return $body['user'];
}
protected function mapUserToObject(array $user)
{
$user['name'] = $user['last_name'] . ' ' . $user['first_name'];
return (new User())->setRaw($user)->map([
'id' => $user['id'],
'name' => $user['name'],
'email' => $user['email'],
'display_name' => $user['display_name'],
'first_name' => $user['first_name'],
'last_name' => $user['last_name'],
'first_name_kana' => $user['first_name_kana'],
'last_name_kana' => $user['last_name_kana'],
]);
}
ログイン認証したユーザトークンを、Configuration クラスに設定
$user = Auth::user();
$config = Configuration::getDefaultConfiguration()->setAccessToken($user->token);
ちなみに、getAccessToken() でアクセストークンを確認できる。
$config->getAccessToken()
CompaniesApi で事業所IDを取得
$companiesApiInstance = new CompaniesApi(null, $config);
$companiesResponse = $companiesApiInstance->getCompanies();
$targetCompanyId = $companiesResponse->getCompanies()[0]->getId();
DealsApi で取引(収入/支出)一覧の取得
$limit = 5;
$dealsApiInstance = new DealsApi(null, $config);
$dealsResponse = $dealsApiInstance->getDeals(
$targetCompanyId,
null, null, null, null, null, null, null, null, null, null, null, null,
$limit);
$deals = $dealsResponse->getDeals();
getDeals() の引数がちょっとどうなんだろ?
freee API は 開発者向けにOSS として公式公開されています。
https://developer.freee.co.jp/
ここでは、リファレンスを利用して認可コード・アクセストークン・API確認をしてみる。
実際の開発は各言語やSDKを使ってコーディングが必要だが、PHPに関しては、freee SDKを Laravel で使ってみる でやってみた。
まず、freeeアカウントを作成(一般ユーザアカウント)する
次に開発ユーザでログインし、開発用テスト環境の作成する。
アプリ追加画面でアプリを追加すると、Client ID, Client secret が発行される
作成したアプリは、アプリ管理 で管理する
「Webアプリ認証用URL」でブラウザでアクセスし、許可すると「認可コード」が発行される
※アクセストークンではない
https://accounts.secure.freee.co.jp/public_api/authorize?client_id={client_id}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=token
上記のURLに freee アプリで発行された Client ID を入れてブラウザでリクエストする
https://developer.freee.co.jp/docs/accounting/reference#/Companies/get_companies
鍵マークをクリック
value に アクセストークンを入力して [Authorize]し、成功したら[Close]
[Try it out] をクリックし [Execute] するとAPIが実行される
curl -X GET "https://api.freee.co.jp/api/1/companies" -H "accept: application/json" -H "Authorization: Bearer {Client ID}"
https://api.freee.co.jp/api/1/companies
{
"companies": [
{
"id": xxxxxxx,
"name": "",
"name_kana": "",
"display_name": "個人事業主名",
"role": "admin"
},
{
"id": xxxxxxx,
"name": null,
"name_kana": null,
"display_name": "個人事業主スタータープラン: 開発用テスト環境",
"role": "admin"
}
]
}
Segue を利用せずに Storyboard の Storyboard ID を利用して present で画面遷移させる。 遷移先の UIViewController を明示的にクラス名を指定すると値を渡すことも可能
let storyboard: UIStoryboard = self.storyboard!
let page = storyboard.instantiateViewController(identifier: "page") as! PageViewController
page.customValue = customValue
page.modalPresentationStyle = .fullScreen
page.modalTransitionStyle = .crossDissolve
self.present(page, animated: true, completion: nil)
.modalPresentationStyle、.modalTransitionStyle プロパティは、iOSバージョンによって異なる
public enum UIModalTransitionStyle : Int {
case coverVertical
case flipHorizontal
case crossDissolve
@available(iOS 3.2, *)
case partialCurl
}
public enum UIModalPresentationStyle : Int {
case fullScreen
@available(iOS 3.2, *)
case pageSheet
@available(iOS 3.2, *)
case formSheet
@available(iOS 3.2, *)
case currentContext
@available(iOS 7.0, *)
case custom
@available(iOS 8.0, *)
case overFullScreen
@available(iOS 8.0, *)
case overCurrentContext
@available(iOS 8.0, *)
case popover
@available(iOS 7.0, *)
case none
@available(iOS 13.0, *)
case automatic
}
Xcode で vim を利用するには「XVim2」をプラグインをインストールすると良い。
(11.3 で動作確認)
XVimProject/XVim2 にあるソースをダウンロード
$ https://github.com/XVimProject/XVim2.git
SIGNING_Xcode.md を参照
Xcodeに署名する
$ sudo codesign -f -s XcodeSigner /Applications/Xcode.app
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
※選択されていない場合は、「xcode-select -s」で選択する
$ cd XVim2
$ make
update_xcode_plugins コマンドを gem でインストール
$ sudo gem install update_xcode_plugins
Password:
Fetching: sync-0.5.0.gem (100%)
Successfully installed sync-0.5.0
...
$ update_xcode_plugins
Found:
- Xcode (11.3.1) [BAB79788-ACEE-4291-826B-EC4667A6BEC5]:
...
$ update_xcode_plugins --unsign
Looking for Xcode...
Unsigning Xcode will make it skip library validation allowing it to load plugins.
However, an unsigned Xcode presents security risks, and will be untrusted by both Apple and your system.
This tool will create a backup and allow you to restore Xcode's signature by running
$ update_xcode_plugins --restore
Choose which Xcode you would like to unsign (use arrows): Xcode (11.3.1) [Signed]: /Applications/Xcode.app
Unsign xcodebuild too?: Yes
...
メニューバー >「Edit」>「XVim」が表示される
Codable を利用して、JSONを 構造体の配列で扱ってみる
JSONのデータにあわせて、Codable クラスの構造体を定義する。
struct HiraganaEntry: Codable {
var word:String
var kana:String
var length:Int
}
カスタムクラスのEntity の配列を定義する
var hiraganaEnties: [HiraganaEntry] = []
Bundle.main.path() でプロジェクト内の JSON ファイルのパスを作成する。
guard let path = Bundle.main.path(forResource: name, ofType: "json") else { return nil }
ファイルパスから UTF-8 で String型で読み込む
let json:String
json = try String(contentsOfFile: path, encoding: .utf8)
JSON(String)を、定義したEntity の配列でデコードする
let entries = try! jsonDecoder.decode([HiraganaEntry].self, from: (json.data(using: .utf8)!))
let jsonDecoder = JSONDecoder()
var hiraganaEnties: [HiraganaEntry] = []
struct HiraganaEntry: Codable {
var word:String
var kana:String
var length:Int
}
func getJSON(name:String) -> Codable? {
let json:String
guard let path = Bundle.main.path(forResource: name, ofType: "json") else { return nil }
do {
json = try String(contentsOfFile: path, encoding: .utf8)
} catch _ {
return nil
}
let entries = try! jsonDecoder.decode([HiraganaEntry].self, from: (json.data(using: .utf8)!))
return entries
}
func loadHiragana() {
hiraganaEnties = getJSON(name: "file_name") as! [GameViewController.HiraganaEntry]
print(hiraganaEnties.randomElement())
}
webpack の環境を構築してみる
参考:webpack 4 入門 webpackの最大の特徴は「モジュールバンドラ」を利用して、複数のjsファイルを1つのファイル「bundle.js」にまとめる。
├── node_modules
├── package.json
├── public
│ ├── index.html
│ └── js
│ └── bundle.js
├── src
│ └── js
│ ├── app.js
│ └── modules
│ ├── add-calculator.js
│ └── tax-calculator.js
└── webpack.config.js
上記の場合「app.js」「add-calculator.js」「tax-calculator.js」をビルドして「bundle.js」にまとめます。
※NodeJS, npm, yarn などは解説省略
$ yarn init --yes
yarn init v1.21.1
warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.
success Saved package.json
✨ Done in 0.04s.
$ yarn add webpack webpack-cli webpack-dev-server --dev
var path = require('path');
module.exports = {
entry: "./src/js/app.js",
output: {
path: path.join(__dirname, 'public/js'),
filename: 'bundle.js',
},
resolve: {
extensions: ['.js', '.ts', '.svg']
},
module: {
rules: [{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}],
}, {
test: /\.ts$/,
use: [{
loader: 'ts-loader',
options: {
compilerOptions: {
declaration: false,
target: 'es5',
module: 'commonjs'
},
transpileOnly: true
}
}]
}, {
test: /\.svg$/,
use: [{
loader: 'html-loader',
options: {
minimize: true
}
}]
}]
}
}
entry:コンパイルするメインJSファイルパス(エントリーポイント)
output:出力するメインJSファイルのパス 最初に require した path を利用して最終的に「public」ディレクトリに「bundle.js」を書き出す
require , importするファイル拡張子を省略設定
ビルドする際、利用するモジュールを設定 babel-loader: Bableに対応する
次世代 EcmaScript で書かれたJSを、サポートしていないブラウザでも動くJSに変換
ts-loader:TypeSceiptに対応する
$ yarn install
yarn install v1.21.1
[1/4] 🔍 Resolving packages...
success Already up-to-date.
✨ Done in 0.12s.
$ mkdir src
export default function addCalculator(number1 ,number2) {
return number1 + number2;
}
import addCalculator from './modules/add-calculator';
import taxCalculator from './modules/tax-calculator';
var item1_price = 100;
var item2_price = 300;
var total_price = addCalculator(item1_price, item2_price);
var tax = 0.1;
var tax_price = taxCalculator(total_price, tax);
window.onload = function() {
document.getElementById('calculate-result').innerHTML = tax_price;
};
export default function taxCalculator(price ,tax) {
return Math.round(price * (1 + tax));
}
$ yarn run webpack
node_modules のパスをbash に登録することで、webpack コマンドを直接利用できる
$ vi ~/.bash_profile
export PATH=$PATH:./node_modules/.bin
$ source ~/.bash_profile
Laradock の接続は psql のバージョンが 12 だとプロトコルエラーとなった。
$ psql -h localhost -U default -l
psql: error: could not connect to server: FATAL: unsupported frontend protocol 1234.5679: server supports 2.0 to 3.0
Macにインストールした psql のバージョンを変更する。
$ which psql
/usr/local/opt/libpq/bin/psql
$brew search postgresql
...
$ brew install postgresql@11
$ alias psql='/usr/local/opt/postgresql@11/bin/psql'