|
6 | 6 |
|
7 | 7 | ## Installation
|
8 | 8 |
|
| 9 | +1. |
| 10 | + |
9 | 11 | ```bash
|
10 | 12 | $ nvm use || nvm install
|
11 | 13 | $ yarn
|
12 | 14 | ```
|
13 | 15 |
|
| 16 | +2. change the import line in `node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts` |
| 17 | + |
| 18 | +```ts |
| 19 | +import { Compiler, WebpackPluginInstance as Plugin } from 'webpack'; |
| 20 | +``` |
| 21 | + |
14 | 22 | ## Running the app
|
15 | 23 |
|
16 | 24 | ```bash
|
@@ -113,10 +121,237 @@ $ mkdir -p src/client/pages
|
113 | 121 | }
|
114 | 122 | ```
|
115 | 123 |
|
116 |
| -6. change the import line in `node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts` |
| 124 | +6. change the import line in `node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts` every time after npm package installation/removal |
117 | 125 |
|
118 | 126 | ```ts
|
119 | 127 | import { Compiler, WebpackPluginInstance as Plugin } from 'webpack';
|
120 | 128 | ```
|
121 | 129 |
|
122 | 130 | 7. create pages in `src/client/pages` folder
|
| 131 | + |
| 132 | +### [Eslint and Prettier](https://dev.to/robertcoopercode/using-eslint-and-prettier-in-a-typescript-project-53jb) |
| 133 | + |
| 134 | +1. |
| 135 | + |
| 136 | +```bash |
| 137 | +$ yarn add -D eslint-plugin-react eslint-import-resolver-typescript eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react-hooks |
| 138 | +``` |
| 139 | + |
| 140 | +2. create `src/client/.eslintrc.js` |
| 141 | + |
| 142 | +```js |
| 143 | +module.exports = { |
| 144 | + root: true, |
| 145 | + env: { |
| 146 | + browser: true, |
| 147 | + node: true, |
| 148 | + es2020: true, |
| 149 | + jest: true, |
| 150 | + }, |
| 151 | + parser: '@typescript-eslint/parser', // Specifies the ESLint parser |
| 152 | + parserOptions: { |
| 153 | + ecmaVersion: 2020, |
| 154 | + sourceType: 'module', |
| 155 | + ecmaFeatures: { |
| 156 | + jsx: true, |
| 157 | + }, |
| 158 | + }, |
| 159 | + plugins: [ |
| 160 | + '@emotion', |
| 161 | + '@typescript-eslint', |
| 162 | + 'react', |
| 163 | + 'react-hooks', |
| 164 | + 'prettier', |
| 165 | + ], |
| 166 | + extends: [ |
| 167 | + 'airbnb', |
| 168 | + 'plugin:@typescript-eslint/recommended', |
| 169 | + 'plugin:react/recommended', |
| 170 | + 'plugin:import/errors', |
| 171 | + 'plugin:import/warnings', |
| 172 | + 'plugin:import/typescript', |
| 173 | + 'prettier', |
| 174 | + 'prettier/@typescript-eslint', |
| 175 | + 'prettier/react', |
| 176 | + '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. |
| 177 | + ], |
| 178 | + rules: { |
| 179 | + '@typescript-eslint/no-unused-vars': [ |
| 180 | + 'error', |
| 181 | + { |
| 182 | + vars: 'all', |
| 183 | + args: 'after-used', |
| 184 | + ignoreRestSiblings: false, |
| 185 | + }, |
| 186 | + ], |
| 187 | + '@typescript-eslint/no-explicit-any': 0, |
| 188 | + '@typescript-eslint/explicit-function-return-type': 0, |
| 189 | + '@typescript-eslint/no-namespace': 0, |
| 190 | + '@typescript-eslint/explicit-module-boundary-types': 0, |
| 191 | + 'import/extensions': [1, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }], |
| 192 | + 'import/no-extraneous-dependencies': [ |
| 193 | + 'error', |
| 194 | + { |
| 195 | + devDependencies: true, |
| 196 | + }, |
| 197 | + ], |
| 198 | + 'react/jsx-filename-extension': [ |
| 199 | + 1, |
| 200 | + { extensions: ['.js', '.jsx', '.ts', '.tsx'] }, |
| 201 | + ], |
| 202 | + 'react/react-in-jsx-scope': 0, |
| 203 | + 'react/jsx-first-prop-new-line': 0, |
| 204 | + 'react/prop-types': 0, |
| 205 | + 'react/jsx-props-no-spreading': [2, { custom: 'ignore' }], |
| 206 | + 'jsx-a11y/anchor-is-valid': [ |
| 207 | + 'error', |
| 208 | + { |
| 209 | + components: ['Link'], |
| 210 | + specialLink: ['hrefLeft', 'hrefRight'], |
| 211 | + aspects: ['invalidHref', 'preferButton'], |
| 212 | + }, |
| 213 | + ], |
| 214 | + 'prettier/prettier': 2, |
| 215 | + 'react-hooks/rules-of-hooks': 2, |
| 216 | + 'react-hooks/exhaustive-deps': 2, |
| 217 | + 'no-bitwise': 2, |
| 218 | + '@emotion/no-vanilla': 2, |
| 219 | + '@emotion/import-from-emotion': 2, |
| 220 | + '@emotion/styled-import': 2, |
| 221 | + }, |
| 222 | + settings: { |
| 223 | + 'import/resolver': { |
| 224 | + node: { |
| 225 | + extensions: ['.js', '.jsx', '.ts', '.tsx'], |
| 226 | + }, |
| 227 | + typescript: {}, |
| 228 | + }, |
| 229 | + react: { |
| 230 | + version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use |
| 231 | + }, |
| 232 | + }, |
| 233 | +}; |
| 234 | +``` |
| 235 | + |
| 236 | +### [Jest](https://medium.com/@miiny/unit-test-next-js-with-jest-and-enzyme-5b305a8e29fe) |
| 237 | + |
| 238 | +1. |
| 239 | + |
| 240 | +```bash |
| 241 | +$ yarn add -D @next/env |
| 242 | +``` |
| 243 | + |
| 244 | +2. modify `jest` config in `package.json` |
| 245 | + |
| 246 | +```json |
| 247 | +{ |
| 248 | + "jest": { |
| 249 | + "moduleFileExtensions": ["js", "json", "ts", "tsx", "jsx"], |
| 250 | + "rootDir": "src", |
| 251 | + "testRegex": ".*\\.spec\\.ts$", |
| 252 | + "transform": { |
| 253 | + "^.+\\.(t|j)s$": "ts-jest" |
| 254 | + }, |
| 255 | + "collectCoverageFrom": ["**/*.(t|j)sx?"], |
| 256 | + "coverageDirectory": "../coverage", |
| 257 | + "coveragePathIgnorePatterns": [ |
| 258 | + "/node_modules/", |
| 259 | + "next.config.js", |
| 260 | + ".json", |
| 261 | + ".snap" |
| 262 | + ], |
| 263 | + "testEnvironment": "node", |
| 264 | + "moduleNameMapper": { |
| 265 | + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/mocks.js", |
| 266 | + "\\.(css|less|scss)$": "<rootDir>/__mocks__/mocks.js" |
| 267 | + }, |
| 268 | + "snapshotSerializers": ["@emotion/jest/serializer"], |
| 269 | + "setupFiles": ["<rootDir>/test/jest.setup.js"], |
| 270 | + "setupFilesAfterEnv": ["<rootDir>/test/jest.setupAfterEnv.js"] |
| 271 | + } |
| 272 | +} |
| 273 | +``` |
| 274 | + |
| 275 | +4. create `src/client/babel.config.js` |
| 276 | + |
| 277 | +```js |
| 278 | +module.exports = { |
| 279 | + presets: ['next/babel'], |
| 280 | +}; |
| 281 | +``` |
| 282 | + |
| 283 | +5. create `test/jest.setup.js` |
| 284 | + |
| 285 | +```js |
| 286 | +import { join } from 'path'; |
| 287 | +import { loadEnvConfig } from '@next/env'; |
| 288 | + |
| 289 | +// to load '.env' files in test |
| 290 | +loadEnvConfig(join(__dirname, '../src/client')); |
| 291 | +``` |
| 292 | + |
| 293 | +### [EmotionJs](https://emotion.sh/docs/install) |
| 294 | + |
| 295 | +1. |
| 296 | + |
| 297 | +```bash |
| 298 | +$ yarn add @emotion/react |
| 299 | +$ yarn add -D @emotion/babel-plugin @emotion/eslint-plugin @emotion/jest |
| 300 | +``` |
| 301 | + |
| 302 | +2. change `src/client/babel.config.js` |
| 303 | + |
| 304 | +```js |
| 305 | +module.exports = { |
| 306 | + presets: [ |
| 307 | + [ |
| 308 | + 'next/babel', |
| 309 | + { |
| 310 | + 'preset-react': { |
| 311 | + runtime: 'automatic', |
| 312 | + importSource: '@emotion/react', |
| 313 | + }, |
| 314 | + }, |
| 315 | + ], |
| 316 | + ], |
| 317 | + plugins: ['@emotion/babel-plugin'], |
| 318 | +}; |
| 319 | +``` |
| 320 | + |
| 321 | +3. add rules and plugins to `.eslintrc.js` |
| 322 | + |
| 323 | +```js |
| 324 | +module.exports = { |
| 325 | + // ... |
| 326 | + rules: { |
| 327 | + // ... |
| 328 | + '@emotion/no-vanilla': 'error', |
| 329 | + '@emotion/import-from-emotion': 'error', |
| 330 | + '@emotion/styled-import': 'error', |
| 331 | + }, |
| 332 | + // ... |
| 333 | + plugins: [ |
| 334 | + '@emotion', |
| 335 | + // ... |
| 336 | + ], |
| 337 | + // ... |
| 338 | +}; |
| 339 | +``` |
| 340 | + |
| 341 | +4. add `test/jest.setupAfterEnv.js` |
| 342 | + |
| 343 | +```js |
| 344 | +import { matchers } from '@emotion/jest'; |
| 345 | + |
| 346 | +expect.extend(matchers); |
| 347 | +``` |
| 348 | + |
| 349 | +5. add to `tsconfig.json` |
| 350 | + |
| 351 | +```json |
| 352 | +{ |
| 353 | + "compilerOptions": { |
| 354 | + "jsxImportSource": "@emotion/react" |
| 355 | + } |
| 356 | +} |
| 357 | +``` |
0 commit comments