この記事について
next.jsを友人と趣味の開発で使用することになったので
しばらく使っていなかった分調べ直して環境構築したメモ
使っているアーキテクチャ
- react
- next
- redux
- typescript
- styled-jsx
ディレクトリ
pages(nextのお作法)
src(componentとか入れる用)
types(typescriptの定義ファイルいれる)
.babelrc
next.config.js
package.json
tsconfig.json
設定
package.json
{
"name": "next-sample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/next": "^6.1.2",
"@types/next-redux-wrapper": "^2.0.0",
"@types/react": "^16.4.11",
"@types/react-redux": "^6.0.6",
"@zeit/next-typescript": "^1.1.0",
"module-alias": "^2.1.0",
"next": "^6.1.1",
"next-redux-wrapper": "^2.0.0",
"react": "^16.4.2",
"react-dom": "^16.4.2",
"react-redux": "^5.0.7",
"redux": "^4.0.0"
},
"devDependencies": {
"@types/node": "^10.9.1",
"babel-plugin-module-resolver": "^3.1.1",
"fork-ts-checker-webpack-plugin": "^0.4.9",
"redux-devtools-extension": "^2.13.5",
"typescript": "^3.0.1"
},
"_moduleAliases": {
"~": "src"
}
}
ポイント
-
_moduleAliases
をつけないと~
をaliasに設定した時typecheckで弾かれる
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"jsx": "preserve",
"allowJs": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": true,
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"~/*": ["src/*"]
},
"noImplicitThis": true,
"lib": [
"dom",
"es2016"
],
"typeRoots":[
"node_modules/@types",
"./types"
],
"rootDirs": ["./pages", "./src"]
}
}
{
"presets": [
"next/babel",
"@zeit/next-typescript/babel"
],
"plugins": [
[
"module-resolver", {
"alias": {
"~": "./src"
}
}
]
]
}
next.config.js
const withTypescript = require('@zeit/next-typescript')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const path = require('path')
module.exports = withTypescript({
webpack(config, options) {
config.resolve.alias = {
...config.resolve.alias,
'~': './src'
}
// typecheckする
if (options.isServer) {
config.plugins.push(new ForkTsCheckerWebpackPlugin())
}
return config
}
})
tsxファイル
_app.tsx
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App, { Container } from 'next/app'
import withRedux from 'next-redux-wrapper'
import { devToolsEnhancer } from 'redux-devtools-extension'
const reducer = (state = {foo: ''}, action) => {
switch (action.type) {
case 'FOO':
return {...state, foo: action.payload};
default:
return state
}
};
const makeStore = (initialState, _) => {
return createStore(
reducer,
initialState,
devToolsEnhancer({})
)
}
interface AppProps {
Component: React.Component
pageProps: any
store: any
}
class MyApp extends App<AppProps> {
static async getInitialProps({ Component, ctx }) {
ctx.store.dispatch({type: 'FOO', payload: 'foo'})
const pageProps =
Component.getInitialProps ? await Component.getInitialProps(ctx) : {}
return { pageProps }
}
render() {
const { Component, pageProps, store } = this.props
return (
<Container>
<Provider store={ store }>
<Component { ...pageProps } />
</Provider>
</Container>
)
}
}
export default withRedux(makeStore)(MyApp)
- storeは
src/store
にディレクトリを作ってやっていく予定 - reduxは使い込んでいないのでいまいちわかっていない。オススメの記事あったら教えてください。
pages/index.tsx
import React, { Component } from 'react'
import { connect } from 'react-redux'
// Components
import DefaultLayout from '~/components/layouts/default'
interface PageProps {
foo: string
custom: string
}
class Page extends Component<PageProps> {
static getInitialProps({ store }) {
store.dispatch({type: 'FOO', payload: 'foo'})
return { custom: 'custom', ...store.getState() }
}
render() {
return (
<DefaultLayout>
<p>Props from Redux { this.props.foo }</p>
<p>Props from getInitialProps { this.props.custom }</p>
<p>welcome to next.js!</p>
<style jsx>
{`
p {
color: red;
}
`}
</style>
</DefaultLayout>
)
}
}
export default connect()(Page)
src/components/layouts/default/index.tsx
interface DefaultLayoutProps {
children: React.ReactNode
}
const DefaultLayout: React.SFC<DefaultLayoutProps> = (props: DefaultLayoutProps) => {
return (
<div>
<header>header</header>
{ props.children }
<footer>footer</footer>
</div>
)
}
export default DefaultLayout
- components内はできるだけSFCで書けるように
-
export const
だとreact dev toolでcomponent名がunknownになっちゃう・・・
types/styled-jsx.d.ts
import 'react'
declare module 'react' {
interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
jsx?: boolean
global?: boolean
}
}
- styled-jsx使うための定義ファイル
最後に
- 環境構築自体は使うものを決めてしまえばやはり使いやすい
- 暫定でやっているところが多いので(特にstore周り)作り込んでいったらテンプレートとしてgithubにおいておきたい
- typescriptは最近使い始めてあんまりわかっていないと思うので、今の時点で何かあれば教えてください
next.jsは1年近く使っていましたが、最近使っていなかったです。
気づいたら_app.jsとかもできてた・・・containerって名前、前のプロジェクトとかでも使っていたけど
もうnextで使われているから気をつけないとと思いました。