Try   HackMD

React Next.js project guide

Next.js

Install Next.js with chakra-ui and TypeScript

  • npx create-next-app [name] --example with-chakra-ui-typescript

Install ESLint and Prettier

  • npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-react prettier

Configire Prettier

  • add .prettierrc
{ "semi": true, "trailingComma": "none", "singleQuote": true, "printWidth": 80, "tabWidth": 2 }

Configire ESLint

  • add .eslintrc
{ "env": { "browser": true, "es6": true, "node": true }, "plugins": ["react", "@typescript-eslint"], "extends": [ "eslint:recommended", "plugin:react/recommended", "next/core-web-vitals", "plugin:@typescript-eslint/eslint-recommended", "prettier" ], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2020, "sourceType": "module" }, "settings": { "react": { "version": "detect" } }, "rules": { /***************************************** * Eslint Rules * DOC: https://eslint.org/docs/rules ****************************************/ "no-console": "off", // suppress errors for missing 'import React' in files "react/react-in-jsx-scope": "off", // React component names must start with an uppercase letter. "react-hooks/rules-of-hooks": "off", /*********************************** * other plugins **********************************/ "@typescript-eslint/no-explicit-any": "off" } }

Configure project settings

  • add .vscode/settings.json
{ // Editor "editor.codeActionsOnSave": { "source.organizeImports": true, "source.fixAll.eslint": true }, "editor.defaultFormatter": "esbenp.prettier-vscode", "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "cSpell.words": [ "Chakra" ] }

Configure i18n

  • npm i next-i18next
  • add next.config.js
const { i18n } = require('./next-i18next.config'); module.exports = { i18n, ... };
  • add next-i18next.config.js
module.exports = { i18n: { defaultLocale: 'en', locales: ['en', 'zh-TW'], localePath: './src/i18n/locales' } };
  • add configuration in _app.tsx
import { appWithTranslation } from 'next-i18next'; const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />; export default appWithTranslation(MyApp);
  • add script in package.json
{ ... "scripts": { ... "locales": "npx prettier --write ./src/i18n/**/*.json" } ... }
  • add locales .sh
# Remember to set script in your package.json # npx prettier --write ./src/i18n/**/*.json # Set the script name in your package.json NPMSCRIPT=locales # Set path and folder names BASE=src/i18n TSFOLDER=localests FOLDER=locales SOURCE=$BASE/$TSFOLDER/* DESTINATION=$BASE/$FOLDER # Remove old files if exist rm -r $DESTINATION # Generate locales folder with only files we need rsync -zarvh $SOURCE $DESTINATION --exclude @types # Point to the BASE folder cd $BASE # Loop through DESTINATION folder for dir in $FOLDER/*; do ( cd "$dir" for FILE in *; do ( # echo $FILE; # remove everything after "import", everything before "=" # remove everything after ";" (deal with ";" being exist in the end) sed -i 's/import.*\|.*=//g;s/;.*//g' $FILE; mv -- "$FILE" "${FILE%.ts}.json"; ) done ) done # Format npm run $NPMSCRIPT # NOTE: # if you excecute "npx prettier --write ./src/i18n/**/*.json" directly here in this script # It will call "$PATH" varible which store in global # The $PATH will be something like this # "/home/yourpcname/.nvm/versions/node/v14.17.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" # Hence you can't point to "./src/i18n/**/*.json" successfully
  • The folder will look like this

  • Alternative JavaScript version of that locales .sh
    Detail

Snippets

  • Open VScode -> File -> Preferences -> User Snippets
  • Type typescriptreact.json
  • Paste!!
{ // Place your snippets for typescriptreact here. Each snippet is defined under a snippet name and has a prefix, body and // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are: // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the // same ids are connected. // Example: "Typescript React PureComponent": { "prefix": "rpc", "body": [ "import * as React from 'react'", "", "export class $1 extends React.PureComponent {", "\trender() {", "\t\treturn ($2);", "}}" ], "description": "Typescript React PureComponent" }, "Twind": { "prefix": "cc", "body": ["className={tw`$1`}"], "description": "Twind" }, "Typescript React Function Component": { "prefix": "rh", "body": [ "import React from 'react'", "", "type ${TM_FILENAME_BASE}Props = {", "$1", "}", "", "const $TM_FILENAME_BASE: React.FC<${TM_FILENAME_BASE}Props> = ({$2}:${TM_FILENAME_BASE}Props) => {", "\t\treturn (<div>${TM_FILENAME_BASE} page!</div>);", "}", "", "export default ${TM_FILENAME_BASE}" ], "description": "Typescript React Function Component" }, "React Native StyleSheet": { "prefix": "rnss", "body": [ "import {StyleSheet} from 'react-native'", "const styles = StyleSheet.create({", "", "});" ], "description": "React Native StyleSheet" }, "Toggle State": { "prefix": "tog", "body": ["this.setState(state => ({", "\topen: !state.open", "}));"], "description": "toggle state" }, "console.log": { "prefix": "cl", "body": ["console.log($1)"], "description": "console.log" }, "className={classnames()}": { "prefix": "cc", "body": ["className={classnames('$1')}"], "description": "tailwind react stuff" }, "Apollo Query Component": { "prefix": "apq", "body": [ "interface Props {", " children: (data: QueryResult<$1, OperationVariables>) => JSX.Element;", "}", "", "export class $2 extends React.PureComponent<Props> {", " render() {", " return (", " <Query<$1> query={$3}>{x => this.props.children(x)}</Query>", " );", " }", "}" ], "description": "Apollo Query Component" } }

Debug

  • You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
    • solution:
      1. npm i next-images
      1. Modify next.config.js
      ​​​​const { i18n } = require('./next-i18next.config'); ​​​​const withImages = require('next-images'); ​​​​module.exports = withImages({ ​​​​ i18n ​​​​});
      1. add @types\images.d.ts in your root path
      ​​​​declare module '*.jpg'; ​​​​declare module '*.jpeg'; ​​​​declare module '*.png';
    • 4.Modify tsconfig.json
      ​​​​{ ​​​​ "compilerOptions": { ​​​​ ... ​​​​ "typeRoots": ["node_modules/@types", "src/@types"] ​​​​ }, ​​​​ ... ​​​​}

Animation

<ScaleFade key={router.route} initialScale={0.98} in={true} transition={{ enter: { duration: 1, delay: 0.2 } }} > <Box minH="70vh" maxW={maxW} w="100%"> {children} </Box> </ScaleFade>

Update history

Newer on the top

Date Author Description
11/02/2022 Alice update
27/01/2022 Alice update
04/06/2021 Alice update
15/05/2021 Alice initial version