初次搭建Next.js项⽬历程(精)
使⽤create-next-app初始化项⽬
create-next-app和react官⽅提供的create-react-app(CRA)⾮常像,next.js官⽅也⾃带了create-next-
app(CNA),所以直接安装就好。
sudo yarn global add create-next-app
安装好之后就可以创建项⽬了
create-next-app project-name
⽣成之后的⽬录结构如下
|-- .gitignore
|-- package.json
|-- yarn.lock
|-- components
| |-- nav.js
|-- pages
| |-- index.js
|-- public
|-- favicon.ico
我们可以查看下package.json
package.json
{
"name": "next-demo4",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "9.1.4",
"react": "16.12.0",
"react-dom": "16.12.0"
}
}
然后执⾏yarn dev运⾏起来试试
配置koa路由
安装好了之后,我们可以设置成koa路由,⾸先添加koa 和 koa-router依赖包,然后在根⽬录下添加server.js⽂件,如下:
yarn add koa koa-router
server.js
const Koa = require("koa");
const next = require("next");
const Router = require("koa-router");
const port = v.PORT, 10) || 3003;
const dev = v.NODE_ENV !== "production";
const app = next({ dev });
const handle = RequestHandler();
app.prepare().then(() => {
const server = new Koa();
const router = new Router();
<("/", async ctx => {
q, s, "/", ctx.query);
});
router.all("*", async ctx => {
await q, s);
});
server.use(async (ctx, next) => {
await next();
});
server.utes());
server.listen(port, () => {
console.log(`> Ready on localhost:${port}`);
});
});
修改package.json⽂件,添加如下代码:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
+ "koa": "node server.js -p 3003"
},
我们现在执⾏yarn koa试试,运⾏成功!
通过next.js官⽅提供的example案例来配置redux 和immutable.js
next.js官⽅案例提供了周边框架的搭建实例,⽅便开发⼈员配置相关框架和插件,如下所⽰:
⾸先我们先来安装redux相关依赖包,如下
yarn add redux redux-actions redux-saga redux-logger
接着我们⼀下我们要搭建的redux和immutable.js相关实例:with-redux-saga和with-immutable-redux-wrapper,然后⾃⼰⼀点点的去配置,当然中间肯定遇到了各种各样的问题,这⾥就不详细说明了,只展⽰配置好运⾏起来没问题的代码分享给⼤家,如下所⽰:
_app.js
import React from "react";
import { Provider } from "react-redux";
import App, { Container } from "next/app";
import withRedux from "next-redux-wrapper";
import withReduxSaga from "next-redux-saga";
import { fromJS } from "immutable";
import configureStore from "../service/redux/store";
import "../assets/styles/index.css";
import "antd/dist/antd.css";
@withRedux(configureStore)
@withReduxSaga
class NextApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (InitialProps) {
pageProps = InitialProps({ ctx });
}
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
js assign<Container>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</Container>
);
}
}
export default NextApp;
store.js
import { createStore, compose, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";
import logger from "redux-logger";
import rootReducer from "./reducers";
import rootSaga from "./sagas";
import { fromJS } from "immutable";
// create the saga middleware
const sagaMiddleware = createSagaMiddleware();
/
/ 组合middleware
const middleWares = [sagaMiddleware, logger];
export default function configureStore(preloadedState = fromJS({})) {
const store = createStore(rootReducer, applyMiddleware(...middleWares));
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
}
reducers.js
import { combineReducers } from "redux";
import { autoCombineReducer } from "../../utils/autoCombineRedux";
export default combineReducers(autoCombineReducer());
sagas.js
import { all, fork } from "redux-saga/effects";
import { autoCombineSaga } from "../../utils/autoCombineRedux";
/*添加对action的监听 */
export default function* rootSaga() {
yield all(autoCombineSaga());
}
这⾥我说明下reducers.js和sagas.js⽤到的⽅法:autoCombineReducer和autoCombineSaga,以前我们写reducer.js或者saga.js是把相关reducer或者saga⽂件import进来,然后注⼊到combineReducers()⽅法或者yield all()⾥⾯,好处是直观,坏处就是每次写⼀个reducer或者saga⽂件就要在这⾥加⼀下,是不是觉得⾮常⿇烦,索性⾃⼰写⼀个⾃动注册进combineReducers()或者yield all()的⽅法,这个⽅法利⽤webpack的t)把⽂件夹下名称为reducer.js或者saga.js⽂件⾃动加载进来,详细请看下⾯代码:
autoCombineRedux.js
import { all, fork } from "redux-saga/effects";
// 查询所有⽂件夹下的所有⽂件名,以⽂件名数组形式返回
const getContext = (path, type) => {
let CONTEXT = type == "reducer" ? t(".", true, /reducer\.js$/) : t(".", true, /saga\.js$/);
if (path == "../") {
CONTEXT = type == "reducer" ? t("../", true, /reducer\.js$/) : t("../", true, /saga\.js$/);
}
if (path == "../../") {
CONTEXT = type == "reducer" ? t("../../", true, /reducer\.js$/) : t("../../", true,
/saga\.js$/);
}
return CONTEXT;
};
export const autoCombineReducer = (path = "../") => {
let CONTEXT = getContext(path, "reducer");
// 获取完组合成reducer对象
const importReducer = req => (obj, path) => {
//从路径中获取reducer name
// output:[0: "demo",groups: undefined,index: 7,input: "./demo/reducer.js"]
const [componentName] = path.match(/\w+(?=\/reducer\.js$)/);
/
/ 组合reducer对象
const reducer = {
[`${componentName}Reducer`]: req(path).default
};
return Object.assign({}, obj, reducer);
};
// 从CONTEXT路径数组中组合成reducer对象返回
const getReducers = ctx => ctx.keys().reduce(importReducer(ctx), {});
return getReducers(CONTEXT);
};
export const autoCombineSaga = (path = "../") => {
let CONTEXT = getContext(path, "saga");
// 获取完组合成reducer对象
const forkSaga = req => path => {
//从路径中获取reducer name
// output:[0: "demo",groups: undefined,index: 7,input: "./ducer.js"]
const [componentName] = path.match(/\w+(?=\/saga\.js$)/);
return fork(req(path).default);
};
// 从CONTEXT路径数组中组合成reducer对象返回
const getSagas = ctx => ctx.keys().map(forkSaga(ctx));
return getSagas(CONTEXT);
};
⼤家有没有发现其实上⾯已经配置好了immutable.js,所以我们就可以直接在reduer⽂件⾥⾯使⽤immutable对象了,如下所⽰:
reducer.js
import { handleActions } from "redux-actions";
import { authTypes } from "./action";
import moment from "moment";
import { Map, fromJS, merge } from "immutable";
const initState = fromJS({
user: null,
token: ""
});
const authReducer = handleActions(
{
[authTypes.AUTH_SUCCESS]: (state, action) => {
({
user: action.data.user,
token: ken
});
},
[authTypes.SIGN_OUT]: (state, action) => {
({
user: null,
token: ""
});
}
},
initState
);
export default authReducer;
这样就完成了redux和immutable.js的配置了,下⾯我们来配置antd。
使⽤next-plugins来配置antd和hiynn-design
ant-design
antd 就不需要我多说明了吧,国内顶级⼤⼚的杰出之作。
hiynn-design
hiynn-design是我公司(海云)前(我)端(创)团(建)队(的)创建的UI库,分为标准化组件和可视化组件。
同样的我们在next.js的example⾥⾯到:with-ant-design-less 我们就100%参考这个实例来配置antd,⾸先我们来添加下相关依赖包:
yarn add @zeit/next-css @zeit/next-sass @zeit/next-less next-compose-plugins less-vars-to-js next-images
yarn add babel-plugin-import @babel/plugin-proposal-decorators @babel/plugin-proposal-do-s @babel/plugin-proposal-class-properties 回过头来我们再来看看next-plugins包含那些插件,如下所⽰:
这⾥就不⼀⼀详细说明了,我们只举⼏个重要的安装包来说明下。
next-images
在SPA项⽬⾥⾯我们使⽤import或者require来加载图⽚,但是next.js不是那么简单的,它会提供你⼀个public ⽂件夹来放静态图⽚,然后写上绝对地址,这样⼀来动态添加图⽚就变得⿇烦,因此就有next-images这个依赖包的出现了,这个包的作⽤是让你像import require那样引⼊你的图⽚。
next-compose-plugins
当我们的fig.js⽂件需要同时配置多个包的时候就会让每个单独配置的包分散开了,这样不利于维护,因此就出现了next-compose-plugins把各个分散的包集合在⼀起,具体的请查看next-compose-plugins
接着我们就按照with-ant-design-less来配置.babelrc和fig.js⽂件,这⾥我们同时⽀持了ant-design和hiynn-design,详细代码如下:
.babelrc
{
"presets": [
"@babel/preset-react", "next/babel"
],
"plugins": [
"@babel/plugin-proposal-do-s",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
//按需加载antd样式
[
"import", {
"libraryName": "antd",
"style": true
},
"antd"
],
//按需加载hiynnd样式
[
"import",
{
"libraryName": "hiynn-design",
"style": true
},
"hiynn-design"
]
]
}
const withCss = require("@zeit/next-css");
const withSass = require("@zeit/next-sass");
const withPlugins = require("next-compose-plugins");
const withLess = require("@zeit/next-less");
const lessToJS = require("less-vars-to-js");
const fs = require("fs");
const path = require("path");
const withImages = require("next-images");
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论