feat: next

This commit is contained in:
NICE CODE BY DEV 2022-05-25 12:33:54 +08:00
parent 671157aee5
commit 551793c036
31 changed files with 583 additions and 34 deletions

12
.babelrc Normal file
View File

@ -0,0 +1,12 @@
{
"presets": ["next/babel"],
"plugins": [
[
"import",
{
"libraryName": "antd",
"style": true
}
]
]
}

2
.env Normal file
View File

@ -0,0 +1,2 @@
NODE_ENV=development
CLIENT_BASE_API=/api

3
.env.pre Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
CLIENT_BASE_API=/api
TTT=pre

3
.env.prod Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
CLIENT_BASE_API=/api
TTT=production

3
.env.release Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
CLIENT_BASE_API=/api
TTT=release

3
.env.test Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
CLIENT_BASE_API=/api
TTT=test

4
.eslintrc.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
extends: [],
rules: {},
};

34
.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

40
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"react",
"typescript",
"typescriptreact",
"vue"
],
"editor.formatOnSave": true,
"[typescriptreact]": {
"editor.defaultFormatter": null
},
"[javascript]": {
"editor.defaultFormatter": null
},
"[typescript]": {
"editor.defaultFormatter": null
},
"[javascriptreact]": {
"editor.defaultFormatter": null
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

View File

@ -1,34 +1 @@
## 目前已有脚手架列表
| 名称 | 说明 | 技术栈 |
| ------- | --------------------------- | --------------------- |
| nextJs | 基于 React 的服务端渲染方案 | nextJs + axios + antd |
| ReactJs | 基于 React 的业务型脚手架 | umiJs + axios + antd |
| TaroJs | 基于 React 的多端适配方案 | TaroJs 全家桶 |
| Vue | 基于 Vue 的业务型脚手架 | vueJs 全家桶 |
| Gulp | 基于 Gulp 的清凉型脚手架 | -- |
## 快速上手
### 1. 安装相关依赖
```js
// 推荐
yarn global add @nicecode/cli
// or
// npm install @nicecode/cli -g
```
### 2. 运行命令
```js
// 查看脚手架版本号,是否安装成功
nice - V
```
### 3. 创建项目
```js
nice create ${项目名称}
```
# nextjs-template

2
next-env.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

67
next-less.config.js Normal file
View File

@ -0,0 +1,67 @@
const cssLoaderConfig = require('@zeit/next-css/css-loader-config');
module.exports = (nextConfig = {}) => {
return Object.assign({}, nextConfig, {
webpack(config, options) {
if (!options.defaultLoaders) {
throw new Error(
'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade',
);
}
const { dev, isServer } = options;
const {
cssModules,
cssLoaderOptions,
postcssLoaderOptions,
lessLoaderOptions = {},
} = nextConfig;
options.defaultLoaders.less = cssLoaderConfig(config, {
extensions: ['less'],
cssModules,
cssLoaderOptions,
postcssLoaderOptions,
dev,
isServer,
loaders: [
{
loader: 'less-loader',
options: lessLoaderOptions,
},
],
});
config.module.rules.push({
test: /\.less$/,
exclude: /node_modules/,
use: options.defaultLoaders.less,
});
// 我们禁用了antd的cssModules
config.module.rules.push({
test: /\.less$/,
include: /node_modules/,
use: cssLoaderConfig(config, {
extensions: ['less'],
cssModules: false,
cssLoaderOptions: {},
dev,
isServer,
loaders: [
{
loader: 'less-loader',
options: lessLoaderOptions,
},
],
}),
});
if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, options);
}
return config;
},
});
};

61
next.config.js Normal file
View File

@ -0,0 +1,61 @@
const withCSS = require('@zeit/next-css');
const withLessExcludeAntd = require('./next-less.config');
const lessToJS = require('less-vars-to-js');
const fs = require('fs');
const path = require('path');
// Where your antd-custom.less file lives
const modifyVars = lessToJS(
fs.readFileSync(
path.resolve(__dirname, './src/styles/antd-custom.less'),
'utf8',
),
);
require('dotenv').config();
module.exports = withLessExcludeAntd(
withCSS({
cssModules: true,
cssLoaderOptions: {
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]',
},
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars, // make your antd custom effective
},
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/;
const origExternals = [...config.externals];
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback();
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback);
} else {
callback();
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
];
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
});
}
// 别名
config.resolve.alias['@'] = path.resolve(__dirname, './src');
config.resolve.alias['@static'] = path.resolve(__dirname, './static');
return config;
},
env: {
CLIENT_BASE_API: process.env.CLIENT_BASE_API,
},
// 用上面的方式使用a[b]的取值取不到
publicRuntimeConfig: {
},
}),
);

58
package.json Normal file
View File

@ -0,0 +1,58 @@
{
"name": "nextjs-template",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "dotenv -e .env next build",
"build:test": "dotenv -e .env.test next build",
"build:release": "dotenv -e .env.release next build",
"build:pre": "dotenv -e .env.pre next build",
"build:production": "dotenv -e .env.prod next build",
"start": "next start",
"lint": "eslint 'src/**/*.{js,jsx,tsx,ts}'",
"lint:fix": "eslint 'src/**/*.{js,jsx,tsx,ts}' --fix",
"prettier": "prettier --write 'src/**/*.{less,css,md,json}'"
},
"dependencies": {
"antd": "^100.0.1",
"axios": "^0.21.1",
"next": "10.0.4",
"normalize.css": "^8.0.1",
"react": "17.0.1",
"react-dom": "17.0.1"
},
"devDependencies": {
"@types/node": "^14.14.19",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/styled-components": "^5.1.7",
"@zeit/next-css": "^1.0.1",
"@zeit/next-less": "^1.0.1",
"babel-plugin-import": "^1.13.3",
"css-loader": "^5.0.1",
"dotenv": "^8.2.0",
"dotenv-cli": "^4.0.0",
"eslint": "^7.32.0",
"less": "3.13.1",
"less-vars-to-js": "^1.3.0",
"lint-staged": "^11.1.2",
"null-loader": "^4.0.1",
"prettier": "^2.3.2",
"typescript": "^4.4.2",
"yorkie": "^2.0.0"
},
"gitHooks": {
"pre-commit": "tsc --noEmit && lint-staged"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"npm run lint:fix",
"git add ."
],
"*.{less,css,md,json}": [
"npm run prettier",
"git add ."
]
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

View File

@ -0,0 +1,3 @@
.container {
width: 500px;
}

View File

@ -0,0 +1,15 @@
import React from 'react';
import { Button } from 'antd';
import styles from './index.less';
const Demo: React.FunctionComponent = () => {
return (
<div className={styles.container}>
<h1>title</h1>
<p>demo</p>
<Button>Button</Button>
</div>
);
};
export default Demo;

View File

@ -0,0 +1,22 @@
import React from 'react';
import Head from 'next/head';
interface PageHeaderProps {
title?: string;
}
const PageHeader: React.FC<PageHeaderProps> = ({ title = 'Uni-Ubi' }) => {
return (
<div>
<Head>
<title>{title}</title>
<link
rel="icon"
href={require('../../../public/favicon.ico')}
/>
</Head>
</div>
);
};
export default PageHeader;

8
src/interfaces/base.ts Normal file
View File

@ -0,0 +1,8 @@
export interface IPagination {
total: number;
size: number;
index: number;
length: number;
beginIndex: number;
endIndex: number;
}

View File

@ -0,0 +1,14 @@
import React from 'react';
import PageHeader from '@/components/PageHeader';
const BasicLayout: React.FC = ({ children }) => {
return (
<div>
<PageHeader />
<main>{children}</main>
</div>
);
};
export default BasicLayout;

7
src/pages/_app.tsx Normal file
View File

@ -0,0 +1,7 @@
import 'normalize.css/normalize.css';
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
export default MyApp;

6
src/pages/api/hello.ts Normal file
View File

@ -0,0 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default (_, res) => {
res.statusCode = 200;
res.json({ name: 'John Doe' });
};

11
src/pages/index.tsx Normal file
View File

@ -0,0 +1,11 @@
import BasicLayout from '@/layouts/BasicLayout';
import Demo from '@/components/Demo';
export default function Home() {
return (
<BasicLayout>
<h1></h1>
<Demo />
</BasicLayout>
);
}

16
src/services/index.ts Normal file
View File

@ -0,0 +1,16 @@
import clientRequest from '@/utils/clientRequest';
export interface HelloWordParams {
pageIndex?: number;
pageSize?: number;
keyword: string;
}
// 获取应用列表
export const helloWordApi = (params: HelloWordParams): Promise<any> =>{
return clientRequest({
url: '/test/helloWord',
params,
});
}

View File

90
src/styles/var.less Normal file
View File

@ -0,0 +1,90 @@
// 颜色
@S1: #25282a;
@S2: #1c21b8;
@S3: #2228e0;
@S4: #4046ff;
@S5: #9ca8ff;
@S6: #c9d2ff;
@M1: #000000;
@M2: #4a4a4a;
@M3: #7c7c7c;
@M4: #959595;
@M5: #c7c7c7;
@M6: #e0e0e0;
@M7: #f2f2f2;
@M8: #f9f9f9;
@M9: #ffffff;
@D1: #fac105;
@D2: #ffab24;
@D3: #ff6952;
@D4: #ff3c73;
@D5: #ee62d5;
@D6: #8475ff;
@D7: #4f73ff;
@D8: #148aff;
@D9: #0cc0c9;
@D10: #0cc991;
@D11: #83d615;
@D1-1: #fef8e5;
@D2-1: #fff6e9;
@D3-1: #fff0ed;
@D4-1: #ffebf1;
@D5-1: #fdeffa;
@D6-1: #f2f1ff;
@D7-1: #edf1ff;
@D8-1: #e7f3ff;
@D9-1: #e6f8f9;
@D10-1: #e6f9f3;
@D11-1: #f2fae7;
@F-info: #4766ff;
@F-success: #46cf84;
@F-warning: #ffa42e;
@F-red: #fa4646;
/* 字体 */
@Fs-1: 12px;
@Fs-2: 14px;
@Fs-3: 16px;
@Fs-4: 18px;
@Fs-5: 20px;
@Fs-6: 22px;
@Fs-7: 24px;
@Fs-8: 28px;
@Fs-9: 32px;
/* 行高 */
@Lh-1: 20px;
@Lh-2: 22px;
@Lh-3: 24px;
@Lh-4: 26px;
@Lh-5: 28px;
@Lh-6: 30px;
@Lh-7: 32px;
@Lh-8: 36px;
@Lh-9: 42px;
// 间距
@Sp-1: 2px;
@Sp-2: 4px;
@Sp-3: 8px;
@Sp-4: 10px;
@Sp-5: 12px;
@Sp-6: 16px;
@Sp-7: 20px;
@Sp-8: 24px;
@Sp-9: 30px;
@Sp-10: 32px;
@Sp-11: 40px;
// 阴影
@Sh-1: 0 0 8px 0 rgba(0, 0, 0, 0.05);
@Sh-2: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
@Sh-3: 0 0 12px 0 rgba(0, 0, 0, 0.1);
@Sh-4: -4px 0 20px 0 rgba(0, 0, 0, 0.1);
@Sh-5: 0 2px 20px 0 rgba(0, 0, 0, 0.3);
// 圆角
@Ra-1: 2px;
@Ra-2: 3px;
@Ra-3: 6px;
@Ra-4: 10px;

View File

@ -0,0 +1,50 @@
import axios from 'axios';
import { message } from 'antd';
import { IPagination } from '@/interfaces/base';
import codeMsg from '@/assets/data/code.json';
export interface BaseResponse {
code: string;
msg: string;
memo?: string;
data: any;
page?: IPagination;
result: number;
success: boolean;
}
const DEFAULT_TIP_MESSAGE = '请求失败,请刷新重试';
const handleError = (data: BaseResponse) => {
const msg = codeMsg[data.code] || data.msg || DEFAULT_TIP_MESSAGE;
message.error(msg);
};
// create an axios instance
const service = axios.create({
baseURL: process.env.CLIENT_BASE_API, // api的base_url
method: 'GET',
// timeout: 5000, // request timeout
});
// request interceptor
service.interceptors.request.use(
(config) => config,
(error) => Promise.reject(error),
);
// response interceptor
service.interceptors.response.use(
(response) => {
const res = response.data;
if (!res.success) {
handleError(res);
}
return res;
},
(error) => {
handleError(error);
return Promise.reject(error);
},
);
export default service;

View File

@ -0,0 +1,21 @@
import axios from 'axios';
// create an axios instance
const service = axios.create({
timeout: 5000, // request timeout
withCredentials: true,
});
// request interceptor
service.interceptors.request.use(
(config) => config,
(error) => Promise.reject(error),
);
// response interceptor
service.interceptors.response.use(
(response) => response,
(error) => Promise.reject(error),
);
export default service;

24
tsconfig.json Normal file
View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@static/*": ["static/*"]
},
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

3
typings.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
declare module '*.png';
declare module '*.css';
declare module '*.less';