1
0
hugo/old/2018-08-25-webpack.md
2024-12-21 16:29:14 +09:00

404 lines
12 KiB
Markdown

+++
date = "2018-08-25"
tags = ["webpack","babel"]
title = "exchatのfrontendをやってみる"
slug = "webpack"
+++
## 導入
昨日、[tony612/exchat](https://github.com/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しません。
```sh
$ 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.
```sh
$ 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が色々出るので。
```sh
$ heroku plugins:install heroku-repo
$ heroku repo:purge_cache
```
## update
色々なパッケージをupdateしていきます。
```sh
$ npm list --depth=0 | grep webpack
# package.json update
$ npm install -g npm-check-updates
$ ncu
$ ncu -u
$ npm update
```
webpackを`1 -> 4`にしたので、だいぶ手こずりました。
一応、成果物を上げておきます。
追記 : 動くようになりました。`react-router@2.x`を指定すると動くのですが、`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
```sh
"react-router" : "git:https://github.com/syui/react-router#v2.8.2"
```
追記終わり。
では、updateした設定ファイルを見ていきます。
> .babelrc
```json
{
"presets": ["react", "es2015", "stage-2"],
"plugins": [
"transform-function-bind"
]
}
```
> package.json
```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
```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
```
```sh
$ 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
```js
- import 'react-select/dist/react-select.css'
```
```sh
$ 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
```js
- 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
```sh
$ 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
```js
- import createLogger from 'redux-logger'
+ import { createLogger } from 'redux-logger'
```
> TypeError: Cannot read property 'listen' of undefined
> unsubscribeFromHistory = history.listen(handleLocationChange);
```sh
"react-router": "^3.0.5",
"react-router-redux": "^4.0.8",
```
ただし、`react-router@2.x`でないと`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`あたりがめんどくさそうでした。
追記 : いけました。ただし、`react-router@2.x`でなければならないのと、`react@15.x -> react@16.x`にしたい場合は、`react-router@2.x`のlib/PropTypesを書き換えなければならない感じでした。