2018-08-25 /
@syui
webpack
, babel
exchatのfrontendをやってみる
導入
昨日、tony612/exchatを扱いましたが、今回はexchatのfrontendの内容になります。
heorkuでは、通常、/app, /webにわけられdeployされます。
なので、phxのようなbackendの成否とreactのようなfrontendの成否は基本的に別々になっています。
つまり、phxのdeployは正常に成功したけど、webpackが失敗して、/webがうまく表示できないなんてこともありえます。
exchatは、backendをelixir(phoenix)で構成し、frontendは、react, reduxなどで構成しているようです。
ここで、frontend(js)のpreview, build, convertなどには、webpack, babelなどを使用しているようです。
今回は、exchatのfrontendの方を少しだけ見ていこうかなと思います。
webpack
buildされたものは、./priv/static/app.js
に置かれるようですね。しかし、.gitignoreに書かれていますので、pushしません。
$ cat webpack.config.js
$ mix deps.get
$ npm i
$ webpack
$ cat ./priv/static/app.js
$ mix phx.server
layoutを変えるには、./web/templates/layout
からhtml:head
より上をいじることもできますが、基本的には、./client/
以下を触ります。
./config/dev.exs
を見ることで、どのようにpreviewされるのかわかります。
riotを触ってた頃、たまたまwebpackも使ってた気がするんですけど、もう忘れてる。
なお、cloudflareとかを利用してる場合、cacheなどが効いてるので、今回生成されるようなapp.jsみたいな一箇所に詰め込まれたファイルというのは、特に、なかなか反映されないことがあります。これは、purgeをするとか、もしくはherokuapp.comで確認するとかしたほうがいいわけですが、それでも反映するまでにしばらく時間がかかることが多いです。browserのprivate windowを利用しても同じ。frontendはこのあたり、大変ですね。あくまで初見の印象ですが。
previewは、$ bash ./compile
したあとに、$ mix phx.server
します。localhost:4000
You are currently using minified code outside of NODE_ENV === ‘production’. This means that you are running a slower development build of Redux. You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) to ensure you have the correct code for your production build.
react
Warning: It looks like you’re using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster. See https://fb.me/react-minification for more details.
$ cat ./compile
info "Building Phoenix static assets"
NODE_ENV=production webpack -p
mix phoenix.digest
$ bash ./compile
どうやら、buildは、NODE_ENV=production webpack -p
すればいいらしいですね。
heroku
./clientを書き換えて、heroku pushしても、全く変更が反映されずにおかしいなと思っていましたが、heroku cacheが効いていたのかもしれません。
./priv/static/js/app.js
を./client/js/app.js
に置き換えることで何故か対応できましたが、errorが色々出るので。
$ heroku plugins:install heroku-repo
$ heroku repo:purge_cache
update
色々なパッケージをupdateしていきます。
$ npm list --depth=0 | grep webpack
# package.json update
$ npm install -g npm-check-updates
$ ncu
$ ncu -u
$ npm update
webpackを1 -> 4
にしたので、だいぶ手こずりました。
一応、成果物を上げておきます。
追記 : 動くようになりました。[email protected]
を指定すると動くのですが、3.x ~ 4.x
では正常に動きません。多分、versionの書き方が必要なのでしょう。特に、prop-typesあたりのコードです。ただし、react 16.xにupdateすると、react-router 2.xには_react.PropType
で書かれた箇所があります。node_modules/react-router/lib/PropType.js
なのですが、現在のsrcでreactをupdateしたい場合は、それを書き換えるしかないですね。
forkしてgithubに上げると、こんな感じで取ってこれます。ただし、webpackで反映されないんで、一旦、npm iしたあとに、再度、本家のversionを指定して、npm iすると、なぜかforkしたlibが読み込まれました。
package.json
"react-router" : "git:https://github.com/syui/react-router#v2.8.2"
追記終わり。
では、updateした設定ファイルを見ていきます。
.babelrc
{
"presets": ["react", "es2015", "stage-2"],
"plugins": [
"transform-function-bind"
]
}
package.json
{
"name": "exchat",
"version": "2.0.0",
"description": "phx chat",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "syui",
"license": "MIT",
"repository": {},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.0.0",
"babel-plugin-transform-function-bind": "^6.22.0",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-2": "^6.5.0",
"webpack": "^4.17.1",
"webpack-cli": "^3.1.0"
},
"dependencies": {
"css-loader": "^1.0.0",
"sass-loader": "^7.1.0",
"resolve-url-loader": "^2.3.0",
"style-loader": "^0.23.0",
"url-loader": "^1.1.1",
"file-loader": "^2.0.0",
"bootstrap-sass": "^3.3.6",
"gravatar": "^1.5.2",
"history": "^4.7.2",
"humps": "^2.0.1",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.3.1",
"jwt-decode": "^2.0.1",
"lodash": "^4.11.2",
"normalizr": "^2.3.0",
"phoenix": "file:./deps/phoenix",
"phoenix_html": "file:./deps/phoenix_html",
"prop-types": "^15.6.2",
"react-bootstrap": "^0.32.3",
"react-select": "^2.0.0",
"react-router-redux": "^4.0.8",
"redux": "^4.0.0",
"redux-thunk": "^2.0.1",
"redux-logger": "^3.0.6",
"react-redux": "^5.0.7",
"react-router": "^2.8.1",
"react": "^15.5",
"react-dom": "^15.5"
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var config = {
mode: 'production',
entry: [
path.resolve(__dirname, './client/js/app.js')
],
output: {
path: path.resolve(__dirname, './priv/static/js'),
filename: 'app.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader : 'babel-loader',
}
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
mimetype: 'application/font-woff'
}
}]
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
mimetype: 'application/font-woff'
}
}]
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
mimetype: 'application/octet-stream'
}
}]
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
limit: '10000',
mimetype: 'image/svg+xml'
}
}]
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
}
]
},
devServer: {
contentBase: path.resolve(__dirname, './client'),
inline: true,
open: true
},
resolve: {
extensions: ['.js', '.jsx', '.scss', '.css']
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
]
}
module.exports = config
$ mix deps.get
$ npm i
$ cat ./compile
./node_modules/webpack-cli/bin/cli.js -p
$ bash ./compile
$ mix phx.server
あとは、以下の箇所のコードを修正しなければいけません。
react-select
Module not found: Error: Can’t resolve ‘react-select/dist/react-select.css’
jsで読み込まれるので最新では必要なくなったらしいです。
./client/js/app.js
- import 'react-select/dist/react-select.css'
$ mix deps.update postgrex
$ bash ./compile
$ mix phx.server
prop-types
React.PropTypes.func : Uncaught ReferenceError: Component is not defined
https://github.com/brigand/babel-plugin-flow-react-proptypes/issues/187
- import React, { PropTypes, Component } from 'react'
+ import React, { Component } from 'react'
+ import PropTypes from "prop-types";
Settings.propTypes = {
- dispatch: React.PropTypes.func
+ dispatch: PropTypes.func
}
こんな感じで直していけばいいです。ファイルは、grep -R PropType . | sort | uniq
とかしましょう。
react-codemod
を使って修正できたりもするようです。しかし、今回のsrcは、skipでした。
Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.x prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs
$ npm install -g jscodeshift
$ git clone https://github.com/reactjs/react-codemod.git
$ echo `pwd`/react-codemod/transforms/React-PropTypes-to-prop-types.js | pbcopy
$ find ./client/js -name "*.js" | xargs jscodeshift -t "`pbpaste`"
28 ok
Time elapsed: 0.000seconds
# skipされるなら以下のコマンド
$ find ./client/js -name "*.js" | xargs jscodeshift --extensions jsx -t "/Users/syui/git/exchat/react-codemod/transforms/React-PropTypes-to-prop-types.js"
$ npm i react react-dom prop-types
normalizr
Uncaught TypeError: normalizr.Schema is not a constructor
これはバージョン下げた。
redux
Uncaught TypeError: (0 , reduxLogger.createLogger) is not a function
redux-logger : ^2.x -> ^3.x
- import createLogger from 'redux-logger'
+ import { createLogger } from 'redux-logger'
TypeError: Cannot read property ’listen’ of undefined
unsubscribeFromHistory = history.listen(handleLocationChange);
"react-router": "^3.0.5",
"react-router-redux": "^4.0.8",
ただし、[email protected]
でないとnpm i -S prop-types
に対応したcodeはうまく動作しない。
react-dom, redux-logger
Uncaught RangeError: Maximum call stack size exceeded
https://github.com/erikras/redux-form/issues/2629
webpack
webpackのversionをいろいろいじってると、config/dev.exsやcompileのwebpackを./node_modules/webpack/bin/webpack.js
から./node_modules/webpack-cli/bin/cli.js
などに変更しなければならないことがあります。もちろん、環境変数でやってもいいですが。
感想
node packageのupdateとかやりましたが、webpackのbuildするのは成功しましたが、やはり./client以下のreactで書かれたcodeが古いので、そちらを書き換えないと表示されない感じでした。残念です。特に、prop-types
あたりがめんどくさそうでした。
追記 : いけました。ただし、[email protected]
でなければならないのと、[email protected] -> [email protected]
にしたい場合は、[email protected]
のlib/PropTypesを書き換えなければならない感じでした。