Open16

記事にするほどでもないけど、無駄に時間を消費してしまった問題の解決方法をまとめるスクラップ

uttkuttk

Next.js + TailwindCSS で本番環境だけCSSが反映されてない

tailwind.config.jspurge の設定がミスっている可能性があるので、そこを設定しなおす。

tailwind.config.js
module.exports = {

   // "/src/" が入ってなかったので、パスが間違っていた
-  purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],

   // 正しいパスを指定してあげる
+  purge: ['./src/pages/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}'],


  /* -- 省略 --*/
}
uttkuttk

Next.js + Firebase Admin SDKのコンパイル時にエラーが発生する

上記のようなエラーが発生した原因は、フロントエンド側のソースコード内でFirebase Admin SDKをimportしているため。

解決方法

Firebase Admin SDKをimportしている部分を削除する事でエラーが無くなる。

因みに、型情報だけ必要な場合は以下のようにしてimportする事が可能なので、覚えておくといいかも?

FirebaseAdminSDKの型情報のみimportする
import type FirebaseAdmin from "firebase-admin";
uttkuttk

注意すること

基本的に、バックエンド用のソースコードを getStaticPropsgetServerSideProps 内だけで使っていると、next.js側がそれを検知してフロントエンド側のバンドルに含めないようにしてくれるが、importだけして使用しないなどの事をしているとエラーが発生する😥

また、人によっては以下のような感じで一つのファイルにまとめている人もいるかもしれない。

/hoge/index.ts
export * from "./client-src"; // フロントエンドのライブラリを含んだソース
export * from "./backend-src"; // バックエンドのライブラリを含んだソース

上記のように、フロントエンド側とバックエンド側のソースコードを混在させてexportしてしまうと、仮にgetStaticPropsgetServerSideProps 内だけでバックエンドのソースコードを使用していても、next.jsが検知してくれずにエラーが発生してしまうので、注意されたし👺

一つのファイルにまとめたいなら、フロントエンドとバックエンドを別々のファイルでまとめると良い。例えば以下のような感じ👇

/hoge/client/index.ts
export * from "./client-src"; // フロントエンドのライブラリを含んだソース
/hoge/backend/index.ts
export * from "./backend-src"; // バックエンドのライブラリを含んだソース
uttkuttk

Zod v3のobject()の型引数に任意の型を渡したい

例えば以下のような実装をしたいが、そのままではエラーが発生してしまう🤯

import * as z from "zod";

interface IHoge {
  hello: string;
  world: string;
}

const Hoge = z.object<IHoge>({ // IHogeを型引数として渡したいが、エラーが発生する
  hello: z.string(),
  world: z.string()
})

上記のエラーを無くすには、zodに渡せる型に変換する型を作って、任意の型を変換してから渡してあげる事でとりあえず解決する👇

import * as z from "zod";

// zodに渡せる型に変換する型
type toZod<T extends Record<string, any>> = {
  [K in keyof T]-?: z.ZodType<T[K]>;
}

interface IHoge {
  hello: string;
  world: string;
}

const Hoge = z.object<toZod<IHoge>>({ // IHogeを型引数として渡したい
  hello: z.string(),
  world: z.string()
})

注意点として、optionalな型があった場合は unknown になってしまうので、
optionalを取り除くために

[K in keyof T]-?: ~

としている🐔

uttkuttk

VSCodeからコミットできない

VSCodeからコミットしようとすると以下のアラートが表示される。

vscodeのエラーアラート画像

.husky/pre-commit: 4: yarn: not found

と出ているので、どうやらhuskyにyarnコマンドが認識されていない様子。
私の環境では、nvmを使用しているので、それが原因だった。

解決策

husky v6からは、.huskyフォルダー下にスクリプトファイルが生成されるので、そこにnvmの環境変数を設定する。

今回の場合は、pre-commitなので.husky/pre-commitファイルを以下のように修正する。

.husky/pre-commit
#!/bin/sh

# nvmの環境変数を設定する
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

# 以下は、記述済みのスクリプト
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged

上記のファイルを保存して、VSCodeからコミットできていればOK👌
もし他のスクリプトがある場合は、.husky/_/husky.shに記述すると良い。

.husky/_/husky.sh
#!/bin/sh
if [ -z "$husky_skip_init" ]; then
  # -- 省略 -- 
fi

# 以下の部分を追加
export NVM_DIR="$HOME/.nvm"
if [ -e $NVM_DIR ]; then
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # nvmがあれば、nvmを有効化する
fi
uttkuttk

Firebase JS SDK v9 で additionalUserInfo を取得する方法

他の認証プロバイダーを使用している場合、そのプロバイダーが提供する情報を additionalUserInfo で取得することができるが、v9では getAdditionalUserInfo() を使わないと取得できないので注意が必要。

以下、サンプルコード👇

import { getAuth, signInWithPopup, getAdditionalUserInfo, GithubAuthProvider } from "firebase/auth"

const onLogin = async () => {
  // Githubのプロバイダーを作成
  const provider = new GithubAuthProvider();

  // ポップアップでログイン
  const result = await signInWithPopup(getAuth(), provider)

  // Github プロバイダーが提供する追加情報を取得する
  const additionalUserInfo = getAdditionalUserInfo(result)

  // 追加情報を表示( profileの値は使っているプロバイダーによって変わります )
  console.log(additionalUserInfo?.profile);
}

参考

https://github.com/firebase/firebase-js-sdk/issues/5257

uttkuttk

Vite で Unable to resolve path to module ~ が出たとき

Vite × React × TypeScript × eslint-plugin-import を使っている環境で、以下のようなエラーが出た 👇

Unable to resolve path to module './App'.

解決策

settings オプションで、拡張子を追加してあげたらエラーが無くなった。

.eslintrc.js
/* -- 省略 -- */
  settings: {
    "import/resolver": {
     node: {
+       extensions: [".js", ".jsx", ".ts", ".tsx"],
      },
   },
  },
/* -- 省略 -- */

具体的な環境情報は以下に載せておく👇

環境情報

バージョン情報

名前 バージョン
vite v2.7.2
react v17.0.2
react-dom v17.0.2
typescript v4.4.4
eslint-plugin-import v2.25.4


設定ファイル情報

.eslint.jsの全体のソースコード(エラーが出た時)
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },

  extends: [
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/recommended",
    "prettier",
  ],

  parser: "@typescript-eslint/parser",

  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 13,
    sourceType: "module",
  },

  plugins: ["react", "@typescript-eslint"],

  ignorePatterns: [".eslintrc.js"],

  overrides: [
    {
      files: ["./src/**/*.{js,jsx,ts,tsx,css,scss,svg}"],
      rules: {
        "import/order": [
          "error",
          {
            groups: ["type", "external", "internal", "sibling"],
            pathGroups: [],
            alphabetize: {
              order: "asc",
            },
            "newlines-between": "always",
          },
        ],
      },
    },
  ],

  rules: {},
};
uttkuttk

Prism.js の自動ハイライトを無効にする

PrismJS は、import<script /> などの方法で読み込まれると highlightAll() を使って自動的にページ内の全てのコードをハイライト( highlight )しようとします。

この挙動を無効にしたい場合は、ページが描画される前に以下の処理を実行します👇

automatic highlight を無効にする処理
window.Prism = window.Prism || {};
window.Prism.manual = true; // 自動的にハイライトするのを無効にする

参照

https://prismjs.com/

uttkuttk

TypeScript で export してない型があるとエラーが発生する

ある時、以下のようなエラーが発生しました👇

tscのエラー内容
モジュールの既定エクスポートがプライベート名 'xxx' を持っているか、使用しています。ts(4082)

問題のソースコードは以下のようになります👇

./a.ts
interface Hoge {
  value: string;
}

export const sayHello = (hoge: Hoge) => {
  console.log(hoge)
}
./b.ts
import { sayHoge  } from "./a";

export const sayHelloWorld = sayHoge; // ここで上記のエラーが発生する

解決策 ①

エラーが発生した原因としては、tsconfig.jsondeclarationtrue に設定すると、プライベートな型を出力できないので、エラーが発生します。なので、declarationfalse に設定するとコードを変更せずに解決できます👇

tsconfig.json
{
  "compilerOptions": {
    /* ... */

    "declaration": false, // ここが true だと上記のエラーが発生する

    /* ... */
  },
}

解決策 ②

interface から type に変更することでもエラーを修正できます👇

./a.ts
- interface Hoge {
+ type Hoge = {
   value: string;
 }

 export const sayHello = (hoge: Hoge) => {
   console.log(hoge)
 }

解決策 ③

プライベートになっている型を export することでもエラーを修正できます👇

./a.ts
- interface Hoge {
+ export interface Hoge {
   value: string;
 }

 export const sayHello = (hoge: Hoge) => {
   console.log(hoge)
 }

参考

https://github.com/microsoft/TypeScript/issues/5711

uttkuttk

ローカル環境で npm へ yarn publish する時にアクセストークンを使う方法

プロジェクトのルートディレクトリ( package.json があるディレクトリ ) に .npmrc を作り、以下のように設定する👇

.npmrc
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

上記のファイルを設定したら、あとは yarn publish するだけ。

参考

https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow#create-and-check-in-a-project-specific-npmrc-file

npm access token の作り方は以下を参照👇

https://docs.npmjs.com/creating-and-viewing-access-tokens

uttkuttk

Vite で TypeError: defaultLoader is not a function なるエラーが発生する

vite を使って react の環境構築をしたときに以下のようなエラーが発生した。

$> npx vite

ailed to load config from vite.config.ts
error when starting dev server:
TypeError: defaultLoader is not a function
...

原因

私の場合、Windowのシンボリックリンクのフォルダー以下でコマンドを実行したことが原因だった。

対処法としては、親フォルダーがシンボリックリンクじゃない場所で、プロジェクトを作りコマンドを実行する必要がある。

参考

https://github.com/vitejs/vite/issues/1493

uttkuttk

.lock ファイルを新しく生成すると突然TypeScriptの型エラーが発生する場合がある

@types/styled-components など一部のパッケージでは、依存関係を定義する際にバージョンを指定していないことがあり、その場合、依存先のバージョンに対応していないがために型エラーが発生する場合がある。

styled-componentsの例
'Hoge' を JSX コンポーネントとして使用することはできません。
  そのインスタンスの型 'Hoge' は、有効な JSX 要素ではありません。
    'render()' によって返された型は、これらの型同士で互換性がありません。
      型 'React.ReactNode' を型 'import("/Hoge/node_modules/@types/styled-components/node_modules/@types/react/index").ReactNode' に割り当てることはできません。
        型 '{}' を型 'ReactNode' に割り当てることはできません。

※ 上記のエラーが出た場合は、使っているパッケージを更新すれば大抵直ります。

このエラーの厄介な所は、.yarn.lock が無い状態で yarn install をしてしまうと、うまくバージョンが解決できずに上記のようなエラーが突然発生してしまう。

そのため、なるべくは .lock ファイルは削除しないようにするべきなんだが、上記のようなことが起きる時は大抵使っているパッケージのバージョンが古いために発生していることが多いので、わざと .lock ファイルを削除して挙動を確かめてみるというは案外いいのかもしれない。

uttkuttk

tsconfig.json で exclude したファイルが TypeScript Auto Import で参照されてしまう問題

以下のように src/exclude.ts を TypeScript のプロジェクトから除外しているのに VSCode などのAuto Import ( Intellisense ) で src/exclude.ts が参照されてしまう問題が発生した 👇

./tsconfig.json
{
  "include": ["src/**/*.ts"],
  "exclude": ["src/exclude.ts"]
}

原因

プロジェクト内のファイルで src/exclude.ts を参照していると、tsconfig.json の exclude を設定していてもプロジェクトファイルとして扱われてしまう。

私の場合だと、src/index.tssrc/exclude.ts をインポートしてしまっていた 👇

./src/index.ts
import { ... } from "./exclude.ts"; 
// 👆 ここで参照したことで tsconfig.json の exclude が無効になってしまう

解決方法

今回の場合は、プロジェクトファイル内で exclude しているファイルを参照しないようにする👇

./src/index.ts
- import { ... } from "./exclude.ts"; 
+ import { ... } from "./non-exclude-file.ts";