项目作者: Project-Setup

项目描述 :
Web app starter with NestJs and NextJs
高级语言: TypeScript
项目地址: git://github.com/Project-Setup/nest-web-app.git
创建时间: 2021-01-13T09:29:20Z
项目社区:https://github.com/Project-Setup/nest-web-app

开源协议:

下载


NestJs NextJs Starter Repository

Description

Nest framework TypeScript starter repository.

Installation

1.

  1. $ nvm use || nvm install
  2. $ yarn
  1. change the import line in node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts
  1. import { Compiler, WebpackPluginInstance as Plugin } from 'webpack';
  1. create MySQL database and account with root (sudo mysql)
  1. CREATE DATABASE example;
  2. ALTER USER 'user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
  3. GRANT ALL ON example.* TO 'user'@'localhost';
  1. create .env.mysql.local with mysql database config environment variables
  1. MYSQL_HOST=localhost
  2. MYSQL_PORT=3306
  3. MYSQL_USERNAME=user
  4. MYSQL_PASSWORD=password
  5. MYSQL_DATABASE=example

Running the app

  1. # development
  2. $ yarn start
  3. # watch mode
  4. $ yarn start:dev
  5. # production mode
  6. $ yarn start:prod

Test

  1. # unit tests
  2. $ yarn test
  3. # e2e tests
  4. $ yarn test:e2e
  5. # test coverage
  6. $ yarn test:cov

Setup

1.

  1. $ nvm use node

NestJs and Fastify

1.

  1. $ npm i -g @nestjs/cli
  2. $ nest new myapp
  3. $ cd myapp
  4. $ yarn add @nestjs/platform-fastify
  1. rearrange the folder structure like this blog

  2. change src/server/main.ts

  1. import { NestFactory } from '@nestjs/core';
  2. import {
  3. FastifyAdapter,
  4. NestFastifyApplication,
  5. } from '@nestjs/platform-fastify';
  6. import { AppModule } from './app.module';
  7. async function bootstrap() {
  8. const app = await NestFactory.create<NestFastifyApplication>(
  9. AppModule,
  10. new FastifyAdapter()
  11. );
  12. await app.listen(3000);
  13. }
  14. bootstrap();
  1. change nest-cli.json
    {
    “collection”: “@nestjs/schematics”,
    “sourceRoot”: “src/server”,
    “entryFile”: “server/main”
    }

NextJs

1.

  1. $ yarn add next react react-dom
  2. $ yarn add -D @types/react-dom @types/react
  3. $ mkdir -p src/client/pages
  1. add to tsconfig.json
  1. {
  2. "compilerOptions": {
  3. "jsx": "preserve"
  4. },
  5. "include": ["src/**/*.ts"]
  6. }
  1. add viewModule similar to this starter repo src/server/modules/view/*.ts

  2. import viewModule in src/server/app.module.ts

  3. add to package.json

  1. {
  2. "resolutions": {
  3. "webpack": "^5.4.0"
  4. }
  5. }
  1. change the import line in node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts every time after npm package installation/removal
  1. import { Compiler, WebpackPluginInstance as Plugin } from 'webpack';
  1. create pages in src/client/pages folder

  2. modify tsconfig.json

  1. {
  2. "include": ["src/**/*", "test/**/*"],
  3. "exclude": ["src/client/.next"]
  4. }

Eslint and Prettier

1.

  1. $ yarn add -D eslint-plugin-react eslint-import-resolver-typescript eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react-hooks
  1. create src/client/.eslintrc.js
  1. module.exports = {
  2. root: true,
  3. env: {
  4. browser: true,
  5. node: true,
  6. es2020: true,
  7. jest: true,
  8. },
  9. parser: '@typescript-eslint/parser', // Specifies the ESLint parser
  10. parserOptions: {
  11. ecmaVersion: 2020,
  12. sourceType: 'module',
  13. ecmaFeatures: {
  14. jsx: true,
  15. },
  16. },
  17. plugins: [
  18. '@emotion',
  19. '@typescript-eslint',
  20. 'react',
  21. 'react-hooks',
  22. 'prettier',
  23. ],
  24. extends: [
  25. 'airbnb',
  26. 'plugin:@typescript-eslint/recommended',
  27. 'plugin:react/recommended',
  28. 'plugin:import/errors',
  29. 'plugin:import/warnings',
  30. 'plugin:import/typescript',
  31. 'prettier',
  32. 'prettier/@typescript-eslint',
  33. 'prettier/react',
  34. 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
  35. ],
  36. rules: {
  37. '@typescript-eslint/no-unused-vars': [
  38. 'error',
  39. {
  40. vars: 'all',
  41. args: 'after-used',
  42. ignoreRestSiblings: false,
  43. },
  44. ],
  45. '@typescript-eslint/no-explicit-any': 0,
  46. '@typescript-eslint/explicit-function-return-type': 0,
  47. '@typescript-eslint/no-namespace': 0,
  48. '@typescript-eslint/explicit-module-boundary-types': 0,
  49. 'import/extensions': [1, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
  50. 'import/no-extraneous-dependencies': [
  51. 'error',
  52. {
  53. devDependencies: true,
  54. },
  55. ],
  56. 'react/jsx-filename-extension': [
  57. 1,
  58. { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
  59. ],
  60. 'react/react-in-jsx-scope': 0,
  61. 'react/jsx-first-prop-new-line': 0,
  62. 'react/prop-types': 0,
  63. 'react/jsx-props-no-spreading': [2, { custom: 'ignore' }],
  64. 'jsx-a11y/anchor-is-valid': [
  65. 'error',
  66. {
  67. components: ['Link'],
  68. specialLink: ['hrefLeft', 'hrefRight'],
  69. aspects: ['invalidHref', 'preferButton'],
  70. },
  71. ],
  72. 'prettier/prettier': 2,
  73. 'react-hooks/rules-of-hooks': 2,
  74. 'react-hooks/exhaustive-deps': 2,
  75. 'no-bitwise': 2,
  76. '@emotion/no-vanilla': 2,
  77. '@emotion/import-from-emotion': 2,
  78. '@emotion/styled-import': 2,
  79. },
  80. settings: {
  81. 'import/resolver': {
  82. node: {
  83. extensions: ['.js', '.jsx', '.ts', '.tsx'],
  84. },
  85. typescript: {},
  86. },
  87. react: {
  88. version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
  89. },
  90. },
  91. };

@miiny/unit-test-next-js-with-jest-and-enzyme-5b305a8e29fe">Jest

1.

  1. $ yarn remove ts-jest
  2. $ yarn add -D @next/env @babel/core babel-jest
  1. modify jest config in package.json
  1. {
  2. "jest": {
  3. "moduleFileExtensions": ["js", "json", "ts", "tsx", "jsx"],
  4. "globals": {
  5. "NODE_ENV": "test"
  6. },
  7. "testRegex": ".*\\.spec\\.(t|j)sx?$",
  8. "transform": {
  9. "^.+\\.(t|j)sx?$": "babel-jest"
  10. },
  11. "collectCoverageFrom": ["**/*.(t|j)sx?"],
  12. "coverageDirectory": "../coverage",
  13. "coveragePathIgnorePatterns": [
  14. "/node_modules/",
  15. "next.config.js",
  16. ".json",
  17. ".snap"
  18. ],
  19. "testEnvironment": "node",
  20. "moduleNameMapper": {
  21. "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/mocks.js",
  22. "\\.(css|less|scss)$": "<rootDir>/test/__mocks__/mocks.js",
  23. "^~(.*)$": "<rootDir>/src/$1"
  24. },
  25. "snapshotSerializers": ["@emotion/jest/serializer"],
  26. "setupFiles": ["<rootDir>/test/jest.setup.js"],
  27. "setupFilesAfterEnv": ["<rootDir>/test/jest.setupAfterEnv.js"]
  28. }
  29. }
  1. create babel.config.js
  1. module.exports = {
  2. presets: ['next/babel'],
  3. };
  1. create symbolic link of babel.config.js to src/client/babel.config.js
  1. $ ln -sf "$(pwd)/babel.config.js" "$(pwd)/src/client"
  1. create test/jest.setup.js
  1. import { join } from 'path';
  2. import { loadEnvConfig } from '@next/env';
  3. // to load '.env' files in test
  4. loadEnvConfig(join(__dirname, '../src/client'));

EmotionJs

1.

  1. $ yarn add @emotion/react
  2. $ yarn add -D @emotion/babel-plugin @emotion/eslint-plugin @emotion/jest
  1. change babel.config.js
  1. module.exports = {
  2. presets: [
  3. [
  4. 'next/babel',
  5. {
  6. 'preset-react': {
  7. runtime: 'automatic',
  8. importSource: '@emotion/react',
  9. },
  10. },
  11. ],
  12. ],
  13. plugins: ['@emotion/babel-plugin'],
  14. };
  1. add rules and plugins to .eslintrc.js
  1. module.exports = {
  2. // ...
  3. rules: {
  4. // ...
  5. '@emotion/no-vanilla': 'error',
  6. '@emotion/import-from-emotion': 'error',
  7. '@emotion/styled-import': 'error',
  8. },
  9. // ...
  10. plugins: [
  11. '@emotion',
  12. // ...
  13. ],
  14. // ...
  15. };
  1. add test/jest.setupAfterEnv.js
  1. import { matchers } from '@emotion/jest';
  2. expect.extend(matchers);
  1. add to tsconfig.json
  1. {
  2. "compilerOptions": {
  3. "jsxImportSource": "@emotion/react"
  4. }
  5. }

Redux-Toolkit

1.

  1. $ yarn add react-redux @reduxjs/toolkit next-redux-wrapper
  2. $ yarn add -D @types/react-redux @types/webpack-env
  1. create custom rootReducer, makeStore, wrapper similar to ones in files src/features/redux/reducers.tsx and src/features/redux/store.tsx and apply them in src/pages/_app.tsx

TypeORM

1.

  1. $ yarn add @nestjs/config @nestjs/typeorm typeorm mysql
  2. # or other database driver
  1. create MySQL database and account with root (sudo mysql)
  1. CREATE DATABASE example;
  2. ALTER USER 'user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
  3. GRANT ALL ON example.* TO 'user'@'localhost';
  1. create .env.mysql.local with mysql database config environment variables
  1. MYSQL_HOST=localhost
  2. MYSQL_PORT=3306
  3. MYSQL_USERNAME=user
  4. MYSQL_PASSWORD=password
  5. MYSQL_DATABASE=example
  1. add typeorm module to imports in src/server/app.module.ts
  1. import { Module } from '@nestjs/common';
  2. import { ConfigModule, ConfigService } from '@nestjs/config';
  3. import { TypeOrmModule } from '@nestjs/typeorm';
  4. @Module({
  5. imports: [
  6. TypeOrmModule.forRootAsync({
  7. imports: [
  8. ConfigModule.forRoot({
  9. envFilePath: '.env.mysql.local',
  10. }),
  11. ],
  12. useFactory: (configService: ConfigService) => ({
  13. type: 'mysql',
  14. host: configService.get('MYSQL_HOST') || 'localhost',
  15. port: configService.get<number>('MYSQL_PORT') || 3306,
  16. username: configService.get('MYSQL_USERNAME'),
  17. password: configService.get('MYSQL_PASSWORD'),
  18. database: configService.get('MYSQL_DATABASE'),
  19. entities: [`${__dirname}/**/*.entity.{ts,js}`],
  20. synchronize: true,
  21. }),
  22. inject: [ConfigService],
  23. }),
  24. ]
  25. }
  1. add entities, services, and modules similar to src/server/modules/user