shujer / Blog

前端相关的文章整理(译文 & 技术解读 & 代码实践)
1 stars 0 forks source link

【Infra】日常问题记录 #6

Open shujer opened 2 years ago

shujer commented 2 years ago

记录日常开发/打包/编译📦遇到的问题 & 解决方案

shujer commented 2 years ago

/ webpackChunkName: "[request]" / is not working in production mode

  1. Usage scenario:use webpack dynamic import with webpack: 5.67.0. work well in development mode but fail in production mode.
    import(/* webpackChunkName: "[request]" */ `i18n/${language}.json`)
  2. Solved Solution: use webpackMode: lazy / lazy-once instead
    import(/* webpackMode: "lazy-once" */ `i18n/${language}.json`)
  3. Expression: see details in https://webpack.js.org/api/module-methods/#magic-comments. use webpackMode to lazyload is a more appropriate way.

    webpackChunkName: A name for the new chunk. Since webpack 2.6.0, the placeholders [index] and [request] are supported within the given string to an incremented number or the actual resolved filename respectively. Adding this comment will cause our separate chunk to be named [my-chunk-name].js instead of [id].js.

webpackMode: Since webpack 2.6.0, different modes for resolving dynamic imports can be specified. The following options are supported:

'lazy' (default): Generates a lazy-loadable chunk for each import()ed module. 'lazy-once': Generates a single lazy-loadable chunk that can satisfy all calls to import(). The chunk will be fetched on the first call to import(), and subsequent calls to import() will use the same network response. Note that this only makes sense in the case of a partially dynamic statement, e.g. import(./locales/${language}.json), where multiple module paths that can potentially be requested.

shujer commented 2 years ago

Invalid hook call. Hooks can only be called inside of the body of a function component.

  1. Usage scenario:use rollup to build library for react component.

  2. Error log:

    Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

    1. You might have mismatching versions of React and the renderer (such as React DOM)
    2. You might be breaking the Rules of Hooks
    3. You might have more than one copy of React in the same app See for tips about how to debug and fix this problem.
  3. Solved Solution: As https://reactjs.org/warnings/invalid-hook-call-warning.html metions:

    In general, React supports using multiple independent copies on one page (for example, if an app and a third-party widget both use it). It only breaks if require('react') resolves differently between the component and the react-dom copy it was rendered with.

we need to check out multiple independent copies in our project. Add external config for rollup.config.js

export default [
  //...
  external: ['react-native', 'react', 'react-dom']
]
shujer commented 2 years ago

[TypeScript - [Subsequent property declarations must have the same type] - Multiple references to the same type definitions

  1. Usage scenario: use monorepo & father-build (babel mode) to build a library
  2. Error logs:

    error TS2717: Subsequent property declarations must have the same type.

  3. Solved Solution: As https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25145 mentions: for different packages, node_modules includes multi-type @types/react(16 & 17 & *). Try to add resolutions into root package.json to solve this problem:
    "resolutions": {
    "@types/react": "16.14.24"
    },
shujer commented 1 year ago

Eslint - error 'console' is not defined / error Unexpected console statement no-console

  1. Usage scenario:use eslint
  2. Error logs:

    error Unexpected console statement no-console error 'console' is not defined no-undef

  3. Solved Solution: when we use env browser may meet this question, modify .eslintrc.js with
    env: {
    es6: true,
    node: true,
    browser: true
    },
shujer commented 1 year ago

React - error 'react' import is duplicated no-duplicate-imports / error 'React' was used before it was defined no-use-before-define / 'React' must be in scope when using JSX react/react-in-jsx-scope

  1. Usage scenario: React >= 17 & eslint & @typescript-eslint
  2. Error logs:

    error 'react' import is duplicated no-duplicate-imports error 'React' was used before it was defined no-use-before-define error 'React' must be in scope when using JSX react/react-in-jsx-scope

  3. Solved Solution: modify eslint rules in .eslintrc.js with
    'no-use-before-define': 'off',
    '@typescript-eslint/no-use-before-define': 'error',
    'react/react-in-jsx-scope': 'off'
shujer commented 1 year ago

Migrate from Vite React TS App To Vite Preact TS App

Step1 - package.json

from

  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^3.1.0"
  }

to

  "dependencies": {
    "preact": "^10.13.1"
  },
  "devDependencies": {
    "@prefresh/vite": "^2.2.9",
  }

Step 2 - tsconfig.json

from

{
  "compilerOptions": {
    "jsx": "react-jsx"
  },
}

to

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact",
  },
}

Step3 - vite.config.ts

from

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
})

to

import { defineConfig } from 'vite'
import preact from '@prefresh/vite'

// https://vitejs.dev/config/
export default defineConfig({
  esbuild: {
    jsxImportSource: 'preact',
    jsxFactory: 'h',
    jsxFragment: 'Fragment'
  },
  plugins: [preact()],
  resolve: {
    alias: {
      react: 'preact/compat',
      'react-dom': 'preact/compat'
    }
  }
})

Step 4 - main.tsx

from

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

to

import React from 'react'
import { render } from 'preact'
import App from './App'

render(<App />, document.getElementById('root') as HTMLElement)
shujer commented 1 year ago

Preact render Blank in Safari ios < 12.4

add plugin https://github.com/vitejs/vite/tree/main/packages/plugin-legacy

// vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default {
  plugins: [
    legacy({
      targets: ['defaults'],
    }),
  ],
}