s2sをdockerで試してみたメモのつづき。
s2sを動かしてみたメモ。
動作環境
- windows10
- vagrant1.9.7
- virtualbox5.1.26
- ubuntu-16.04
- Docker version 17.09.0-ce, build afdb6d4
- docker-compose version 1.17.1, build 6d101fb
ディレクトリ構成
- app
- docker
- s2s
- Dockerfile
- docker-compose.yml
+ src
エディタの環境設定
Flowは使ったことがなかったのでVSCodeの拡張を適用。
Flow Language Support
とflow-vscode-ide
をとりあえずいれてみた。
npm i -D flow flow-bin
{
"devDependencies": {
"flow": "^0.2.3",
"flow-bin": "^0.59.0"
}
}
{
"files.associations": {
"*.js": "javascriptreact"
}
,"javascript.validate.enable": false
,"flow.useNPMPackagedFlow": true
,"flow.pathToFlow": "./node_modules/.bin/flow"
}
実践
さよならボイラーテンプレートのshopping-cartを試す。
起動
cd docker && docker-compose up
でs2sを起動。
actionTypes.jsの作成
まずは、actionTypes.jsを作成してみる。
空のファイルを作って名前をつけて保存する。
以下の文がs2sによって記述される。
// @flow
export const Actions = {};
export type Action = ;
no such file or directory
とかのエラーが出ているけれど、まだreducer.jsを作っていないので無視。
actionTypes.jsのActionにAddを追加
次に、export type Action = ;
を完成させる。
export type Action = Add;
まで書いて保存する。
以下のように補完される。
// @flow
export const ADD: 'App/ADD' = 'App/ADD'
export const Actions = {
ADD,
}
export type Add = {
type: typeof ADD,
}
export type Action = Add
さらにactions.jsを作成してくれる。
// @flow
import { ADD } from './actionTypes'
import type { Add } from './actionTypes'
export function add(): Add {
return {
type: ADD,
}
}
actionに変数nを追加
n: number
を以下のように追加して保存。
// @flow
export const ADD: 'App/ADD' = 'App/ADD'
export const Actions = {
ADD,
}
export type Add = {
type: typeof ADD,
n: number,
}
export type Action = Add
actions.jsが更新される。
// @flow
import { ADD } from './actionTypes'
import type { Add } from './actionTypes'
export function add(n: number): Add {
return {
type: ADD,
n,
}
}
reducerの作成
空のファイルreducer.jsを作成する。
以下の文がs2sによって記述される。
// @flow
import type { Action } from '../../types'
import { Actions } from './actionTypes'
export type State = {}
export const initialState: State = {}
export default function(
state: State = initialState,
action: Action
): Exact<State> {
switch (action.type) {
default:
return state
}
}
さらに、reducer.test.jsも作成される。
// @flow
import reducer, { initialState } from './reducer'
import * as actions from './actions'
test('provide the initial state', () => {
expect(reducer(undefined, { type: '@@INIT' })).toEqual(initialState)
})
Actionの追加
reducer.jsがある状態で、actionTypes.jsを再度保存すると、reducer.jsにcaseが追加される。
// @flow
import type { Action } from '../../types'
import { Actions } from './actionTypes'
export type State = {}
export const initialState: State = {}
export default function(
state: State = initialState,
action: Action
): Exact<State> {
switch (action.type) {
case Actions.ADD:
return {
...state,
}
default:
return state
}
}
reducer.test.jsも更新される。
// @flow
import reducer, { initialState } from './reducer'
import * as actions from './actions'
test('provide the initial state', () => {
expect(reducer(undefined, { type: '@@INIT' })).toEqual(initialState)
})
test('handle ADD', () => {
expect(reducer(initialState, actions.add())).toEqual({})
})
stateの追加
reducer.jsのexport type State = {}
をexport type state={count:number}
に変更する。
保存すると、initialStateが設定される。
export const initialState: State = { count: 0 }
reducerの完成(手作業)
自動化されているのはここまでっぽい。
Addのときに、nをcountに追加する部分を記述。
// @flow
import type { Action } from '../../types'
import { Actions } from './actionTypes'
export type State = { count: number }
export const initialState: State = { count: 0 }
export default function(
state: State = initialState,
action: Action
): Exact<State> {
switch (action.type) {
case Actions.ADD:
return {
...state,
count: state.count + action.n,
}
default:
return state
}
}
reducer.test.jsにactions.add()の引数と、toEqualの結果を記述。
// @flow
import reducer, { initialState } from './reducer'
import * as actions from './actions'
test('provide the initial state', () => {
expect(reducer(undefined, { type: '@@INIT' })).toEqual(initialState)
})
test('handle ADD', () => {
expect(reducer(initialState, actions.add(2))).toEqual({count: 2})
})
テスト確認
package.jsonにテストを動かすスクリプトが書かれていたので実行してみる。
cd docker && docker-compose run s2s npm run test
s2sのサンプルを動かした環境
srcディレクトリ内にはgitからshopping-cartのsrcをコピー。
version: '3'
services:
s2s:
build: ./s2s
volumes:
- ../src:/app/s2s/examples/shopping-cart/src
- ./config/.flowconfig:/app/s2s/example/shopping-cart/.flowconfig
- ./config/s2s.config.js:/app/s2s/example/shopping-cart/s2s.config.js
command: [yarn, run, s2s]
FROM node:9.2.0
# コンテナ上の作業ディレクトリ作成
WORKDIR /app
# ソースダウンロード
RUN git clone --depth=1 https://github.com/akameco/s2s.git
# chokidarのポーリング設定
RUN sed -i -e "s/\(ignoreInitial: true,\)/\1\n usePolling: true, /g" /app/s2s/packages/s2s-cli/src/index.js
# s2sをビルド
WORKDIR /app/s2s/
RUN yarn
# example用設定
WORKDIR /app/s2s/examples/shopping-cart
RUN yarn
RUN yarn run flow
// @flow
const plugins = require('s2s-plugins-redux')
module.exports = {
watch: './**/*.js',
plugins,
templates: [
{ test: /containers\/.*\/index.js/, input: 'containers.js' },
{ test: /components\/.*\/index.js/, input: 'components.js' },
{ test: /components\/.*\/index.test.js/, input: 'component.test.js' },
{ test: /reducer.js/, input: 'reducer.js' },
{ test: /reducer.js/, input: 'reducer.test.js', output: 'reducer.test.js' },
{ test: /reducer.js/, input: 'actionTypes.js', output: 'actionTypes.js' },
{ test: /selectors.js/, input: 'selectors.js' },
{ test: /selectors.test.js/, input: 'selectors.test.js' },
{ test: /logic.js/, input: 'logic.js' },
],
}
[ignore]
.*/templates/.*
[include]
[libs]
[lints]
[options]
ブラウザで実行確認
cd docker && docker-compose up
そのまま動かそうとしたら以下のエラー。
Uncaught TypeError: Cannot read property 'apply' of undefined
at compose.js:29
at createStore (createStore.js:51)
at exports.default (store.js:10)
at Object.<anonymous> (index.js:10)
at __webpack_require__ (bootstrap 7bc4a4fa37f65eb57f87:19)
at Object.<anonymous> (bundle.js:2296)
at __webpack_require__ (bootstrap 7bc4a4fa37f65eb57f87:19)
at module.exports (bootstrap 7bc4a4fa37f65eb57f87:62)
at bootstrap 7bc4a4fa37f65eb57f87:62
store.jsの window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
でエラーが出ていた。
redux-devtools-extension にしたがいRedux DevToolsをchromeに追加。
動いた。
動作確認環境
ディレクトリ構成
- app
- docker
- config
- .babelrc
- .flowconfig
- s2s.config.js
- webpack.config.js
- s2s
- Dockerfile
- webpack
- Dockerfile
- docker-compose.yml
+ src
+ public
ブラウザで確認した環境
publicディレクトリ内にはgitからshopping-cartのpublicをコピー。
ブラウザで確認するためにwebpack-dev-serverを使用する。
version: '3'
services:
s2s:
build: ./s2s
volumes:
- ../src:/app/s2s/examples/shopping-cart/src
- ./config/.flowconfig:/app/s2s/example/shopping-cart/.flowconfig
- ./config/s2s.config.js:/app/s2s/example/shopping-cart/s2s.config.js
command: [yarn, run, s2s]
webpack:
build: ./webpack
volumes:
- ../src:/app/src
- ./config/.flowconfig:/app/.flowconfig
- ./config/.babelrc:/app/.babelrc
- ./config/webpack.config.js:/app/webpack.config.js
- ../public:/app/public
- ../dist:/app/dist
ports:
- 8080:8080
command: [npm, run, dev-server, --, --history-api-fallback]
FROM node:9.2.0
# コンテナ上の作業ディレクトリ作成
WORKDIR /app
# package.jsonを作成
RUN npm init -y
# ビルドツール
RUN npm i -D webpack
# 開発用サーバ
RUN npm i -D webpack-dev-server
# es6用トランスパイラ
RUN npm i -D babel-loader
RUN npm i -D babel-preset-es2015
RUN npm i -D babel-preset-react
RUN npm i -D babel-preset-stage-2
# flow
RUN npm i -D flow
RUN npm i -D flow-bin
RUN npm i -D babel-plugin-transform-flow-strip-types
# jsViewライブラリreact
RUN npm i -S react
RUN npm i -S react-dom
RUN npm i -S react-redux
RUN npm i -S react-scripts
# フレームワーク
RUN npm i -S redux
RUN npm i -S redux-thunk
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n \"flow\": \"flow\",/g" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n \"babel\": \"babel\",/g" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n \"webpack\": \"webpack\",/g" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n \"dev-server\": \"webpack-dev-server\", /g" /app/package.json
{
"presets": [
"react",
"es2015",
"stage-2"
],
"plugins": [
"transform-flow-strip-types"
]
}
[ignore]
.*/templates/.*
.*/node_modules/.*
[include]
[libs]
[lints]
[options]
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: '/app/dist'
},
devtool: "source-map",
resolve: {
extensions: [".jsx", ".js"]
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
},
performance: {
hints:false
},
devServer: {
// public/index.htmlをデフォルトのホームとする
contentBase: './public',
// インラインモード
inline: true,
// 8080番ポートで起動
port: 8080,
// dockerのコンテナ上でサーバを動かすときは以下の設定で全ての接続を受け入れる
host:"0.0.0.0",
},
// vagrantの仕様でポーリングしないとファイルの変更を感知できない
watchOptions: {
aggregateTimeout: 300,
// 5秒毎にポーリング
poll: 5000
}
};
参考
type can be used by only '.ts' files
Visual Studio CodeでFlowTypeのエラーを表示する
さよならボイラープレート。s2sによる高速reduxアプリケーション構築
Flowを使ってアプリケーション開発するためのエディタ環境いろいろ
Flow導入時に最初にやることまとめ
React + flow + Webpackの最小構成
webpack history api fallback