Closed42

nuxt/content v2 に置き換えてみる

ひとまず愚直にマイグレーションに従ってみる

  "dependencies": {
    "@nuxt/content": "^1.15.1",
    "core-js": "^3.21.1",
    "nuxt": "2.13.3"
  },

  "dependencies": {
    "@nuxt/content": "^2.0",
    "nuxt": "^3.0.0-rc.3"
  },

に変更(core-jsなんで入れたか忘れた…)

あとは TypeScript 周りもいらないかもしれないので

    "@nuxt/types": "^2.15.3",
    "@nuxt/typescript-build": "^2.1.0",

上記も削除してみる

npm scripts まわりも更新

    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "dev": "nuxt dev",
    "build": "nuxt build",
    "generate": "nuxt generate",
    "preview": "nuxt preview",

Global Components を差し替え

- components/global
+ components/content

Fetching Content まわりはだいぶ変わってるのでまず読んでみる

There is no global $content variable, instead you can use queryContent composable to fetch contents.

グローバル変数 $content はないが、代わりに queryContent composable を使用してコンテンツを取得することができる。

const posts = await this.$content('/blog', { deep: true }).only(['title']).fetch()

と書いてたのが

const { data: posts } = await useAsyncData('posts-list', () => queryContent('/blog').only(['title']).find())

となる

queryContent provide same utilities as legacy $content with some improvements:

queryContent は従来の $content と同じユーティリティを提供しているが、いくつかの改良が加えられている。

  • fetch dropped in favor of new find utils
    • find: retrieve a list of contents
    • findOne: retrive first matched content
  • surround dropped in favor of findSurround
  • where utility can be chained
  • There is no search utility for full text search.
  • Find utilities does not contains body of documents and they only include meta information of parsed contents. You can fetch contents body using getContentDocument(non-reactive) or useContentDocument(reactive) composables
  • There is new findNavigation utility to retrieve navigation object
  • fetch が廃止、新しい find ユーティリティが採用
    • find : コンテンツのリストを取得
    • findOne: 最初にマッチしたコンテンツを取得
  • surround が削除、findSurround が採用
  • where ユーティリティが繋げて使えるようになった
  • 全文検索のための search ユーティリティはない
  • find ユーティリティはドキュメントの本文を含まず、パースされたコンテンツのメタ情報のみを含む。コンテンツ本体は、getContentDocument (non-reactive) あるいは useContentDocument (reactive) 変数を使って取得できる
  • ナビゲーションオブジェクトを取得するための新しく findNavigation ユーティリティが追加

Rendering Content まわりも見てみる

<NuxtContent> component removed in favor of a <ContentRenderer> component.
<ContentDoc> component receive document path then fetch and render the document.

<NuxtContent> コンポーネントは削除され、<ContentRenderer> コンポーネントが採用された。
<ContentDoc> コンポーネントは、ドキュメントのパスを受け取り、ドキュメントを fetch してレンダリングする。

You can go even faster if you know that route.path will be the same as your content files, use the <ContentDoc> component:

ルートパスがコンテンツファイルと同一なのが分かっている場合は、<ContentDoc> コンポーネントを使用すると、さらに高速に処理することができる。

The <ContentDoc> component will fetch the document for the current route path and use <ContentRenderer> to render it.

<ContentDoc> コンポーネントは、現在のルートパスのドキュメントを取得し、<ContentRenderer> を使用してレンダリングする。

script setup 対応にしたいけどガッと変えることができるだろうかーだろうかー

layout を変更した

https://github.com/yamanoku/archives/pull/54/commits/def723b50ed3992cc25a1e379e6c2969dcdecc51
 <template>
-  <div>
-    <global-header />
-    <nuxt />
-    <global-footer />
-  </div>
+  <global-header />
+  <slot />
+  <global-footer />
 </template>
 
-<script lang="ts">
-import Vue from 'vue'
+<script lang="ts" setup>
 import GlobalHeader from '@/components/global/Header.vue'
 import GlobalFooter from '@/components/global/Footer.vue'
-
-export default Vue.extend({
-  components: {
-    GlobalHeader,
-    GlobalFooter,
-  },
-})
 </script>

index.vue

https://github.com/yamanoku/archives/pull/54/commits/ca7526311c376509ee23984b9c468988649a6042#diff-02281a80fab758cb4e8e8359b222a8a5afeaa9d5a7ba858f15d852f1f8969ecf
-          <nuxt-link :to="article.path">
-            <budoux-ja>
-              {{ article.title }}
-            </budoux-ja>
+          <nuxt-link :to="article._path">
+            {{ article.title }}
           </nuxt-link>
         </h2>
         <p>
@@ -29,79 +27,66 @@
   </main>
 </template>
 
-<script>
-import Vue from 'vue'
-import dayjs from 'dayjs'
+<script setup lang="ts">
+import dayjs from 'dayjs';
 
-Vue.config.ignoredElements = ['budoux-ja']
+const { data: articles } = await useAsyncData('home', () => queryContent('/').sort({'date': 0}).find());
 
-export default {
-  async asyncData({ $content }) {
-    const query = $content('/', { deep: true }).sortBy('date', 'desc')
-    const articles = await query.fetch()
-    return {
-      articles,
-    }
-  },
-  head() {
-    return {
-      title: 'アーカイブ',
-      meta: [
-        {
-          hid: 'description',
-          name: 'description',
-          content:
-            'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
-        },
-        {
-          hid: 'og:title',
-          property: 'og:title',
-          content: 'アーカイブ',
-        },
-        {
-          hid: 'og:description',
-          property: 'og:description',
-          content:
-            'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
-        },
-        {
-          hid: 'og:image',
-          property: 'og:image',
-          content: 'https://yamanoku.net/ogp/ogp-archive@2x.png',
-        },
-        {
-          hid: 'og:image:alt',
-          property: 'og:image:alt',
-          content: 'Archive Document',
-        },
-        {
-          hid: 'twitter:title',
-          name: 'twitter:title',
-          content: 'アーカイブ',
-        },
-        {
-          hid: 'twitter:description',
-          name: 'twitter:description',
-          content:
-            'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
-        },
-        {
-          hid: 'twitter:image',
-          property: 'twitter:image',
-          content: 'https://yamanoku.net/ogp/ogp-archive@2x.png',
-        },
-        {
-          hid: 'twitter:image:alt',
-          property: 'twitter:image:alt',
-          content: 'Archive Document',
-        },
-      ],
-    }
-  },
-  methods: {
-    dateTime(time) {
-      return dayjs(time).format('YYYY-MM-DD')
+const dateTime = (time: string):string => {
+  return dayjs(time).format('YYYY-MM-DD')
+};
+
+useHead({
+  title: 'アーカイブ',
+  meta: [
+    {
+      hid: 'description',
+      name: 'description',
+      content:
+        'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
+    },
+    {
+      hid: 'og:title',
+      property: 'og:title',
+      content: 'アーカイブ',
+    },
+    {
+      hid: 'og:description',
+      property: 'og:description',
+      content:
+        'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
+    },
+    {
+      hid: 'og:image',
+      property: 'og:image',
+      content: 'https://yamanoku.net/ogp/ogp-archive@2x.png',
+    },
+    {
+      hid: 'og:image:alt',
+      property: 'og:image:alt',
+      content: 'Archive Document',
+    },
+    {
+      hid: 'twitter:title',
+      name: 'twitter:title',
+      content: 'アーカイブ',
+    },
+    {
+      hid: 'twitter:description',
+      name: 'twitter:description',
+      content:
+        'このページはyamanokuこと大山奥人が書いてきた過去の記事やログを収集したページです。',
+    },
+    {
+      hid: 'twitter:image',
+      property: 'twitter:image',
+      content: 'https://yamanoku.net/ogp/ogp-archive@2x.png',
+    },
+    {
+      hid: 'twitter:image:alt',
+      property: 'twitter:image:alt',
+      content: 'Archive Document',
     },
-  },
-}
+  ]
+});
 </script>

slug.vue は [...slug].vue に改名してアップデート

https://github.com/yamanoku/archives/pull/54/commits/ca7526311c376509ee23984b9c468988649a6042#diff-575d0b4cf7e94b73d7e421f4482180f1832f172bfef28701cf37a48f51d2a17d

nuxt-content から content-renderer に置き換え対応

- <nuxt-content :document="page" />
+ <content-renderer :value="page" />

<script> 部分

<script setup lang="ts">
import dayjs from 'dayjs'
import DeprecationAlertOneYear from '@/components/global/DeprecationAlertOneYear.vue'
const dateTime = (time: string):string => {
  return dayjs(time).format('YYYY-MM-DD')
};
const { path } = useRoute();
const { data: page } = await useAsyncData(`content-${path}`, () => {
  return queryContent().where({ _path: path }).findOne()
});
const gitHubLink = computed(() => {
  return `https://github.com/yamanoku/archives/issues/new?title=アーカイブのドキュメントにまつわる修正依頼&labels=feedback&body=URL:https://archives.yamanoku.net${path}%0A修正依頼内容:%0A`
});
const twitterLink = computed(() => {
  return `https://twitter.com/share?url=https://archives.yamanoku.net${path}&text=@yamanoku`;
});
const editLink = computed(() => {
  return `https://github.com/yamanoku/archives/edit/main/content${path}.md`;
});
useHead({
  title: page.title,
  meta: [
    {
      hid: 'description',
      name: 'description',
      content: page.description,
    },
    {
      hid: 'og:title',
      property: 'og:title',
      content: page.title,
    },
    {
      hid: 'og:description',
      property: 'og:description',
      content: page.description,
    },
    {
      hid: 'og:image',
      property: 'og:image',
      content: `https://archives.yamanoku.net/og-images${path}.png`,
    },
    {
      hid: 'og:image:alt',
      property: 'og:image:alt',
      content: page.title,
    },
    {
      hid: 'twitter:title',
      name: 'twitter:title',
      content: page.title,
    },
    {
      hid: 'twitter:description',
      name: 'twitter:description',
      content: page.description,
    },
    {
      hid: 'twitter:image',
      property: 'twitter:image',
      content: `https://archives.yamanoku.net/og-images${path}.png`,
    },
    {
      hid: 'twitter:image:alt',
      property: 'twitter:image:alt',
      content: page.title,
    },
  ]
});
</script>

中身が undefined になっていたのだが value で呼び出す必要があった

useHead({
-  title: page.title,
+  title: page.value.title,
  meta: [
    {
      hid: 'description',
      name: 'description',
-      content: page.description,
+      content: page.value.description,
    },
    {
      hid: 'og:title',
      property: 'og:title',
-      content: page.title,
+      content: page.value.title,
    },
    {
      hid: 'og:description',
      property: 'og:description',
-      content: page.description,
+      content: page.value.description,
    },
    {
      hid: 'og:image',
      property: 'og:image',
      content: `https://archives.yamanoku.net/og-images${path}.png`,
    },
    {
      hid: 'og:image:alt',
      property: 'og:image:alt',
-      content: page.title,
+      content: page.value.title,
    },
    {
      hid: 'twitter:title',
      name: 'twitter:title',
-      content: page.title,
+      content: page.value.title,
    },
    {
      hid: 'twitter:description',
      name: 'twitter:description',
-      content: page.description,
+      content: page.value.description,
    },
    {
      hid: 'twitter:image',
      property: 'twitter:image',
      content: `https://archives.yamanoku.net/og-images${path}.png`,
    },
    {
      hid: 'twitter:image:alt',
      property: 'twitter:image:alt',
-      content: page.title,
+      content: page.value.title,
    },
  ]
});

置き換えしてみて立ち上げてみる

ぬーん

file:///Users/yamanoku/archives/.nuxt/dev/index.mjs:34
import { visit } from 'file:///Users/yamanoku/archives/node_modules/unist-util-visit/index.js';
         ^^^^^
SyntaxError: Named export 'visit' not found. The requested module 'file:///Users/yamanoku/works/archives/node_modules/unist-util-visit/index.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'file:///Users/yamanoku/archives/node_modules/unist-util-visit/index.js';
const { visit } = pkg;

    at ModuleJob._instantiate (internal/modules/esm/module_job.js:124:21)
    at async ModuleJob.run (internal/modules/esm/module_job.js:179:5)
    at async Loader.import (internal/modules/esm/loader.js:178:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)
    at async handleMainPromise (internal/modules/run_main.js:59:12)

npm why してみた

$ npm why unist-util-visit

unist-util-visit@2.0.3 dev
node_modules/unist-util-visit
  unist-util-visit@"^2.0.3" from rehype-plugin-auto-resolve-layout-shift@1.0.0
  node_modules/rehype-plugin-auto-resolve-layout-shift
    dev rehype-plugin-auto-resolve-layout-shift@"1.0.0" from the root project
  unist-util-visit@"^2.0.3" from rehype-plugin-image-native-lazy-loading@1.2.0
  node_modules/rehype-plugin-image-native-lazy-loading
    dev rehype-plugin-image-native-lazy-loading@"1.2.0" from the root project

unist-util-visit@4.1.0
node_modules/hast-util-raw/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from hast-util-raw@7.2.1
  node_modules/hast-util-raw
    hast-util-raw@"^7.2.0" from rehype-raw@6.1.1
    node_modules/rehype-raw
      rehype-raw@"^6.1.1" from @nuxt/content@2.0.0
      node_modules/@nuxt/content
        @nuxt/content@"^2.0" from the root project

unist-util-visit@3.1.0
node_modules/mdast-util-definitions/node_modules/unist-util-visit
  unist-util-visit@"^3.0.0" from mdast-util-definitions@5.1.0
  node_modules/mdast-util-definitions
    mdast-util-definitions@"^5.0.0" from mdast-util-to-hast@12.1.1
    node_modules/mdast-util-to-hast
      mdast-util-to-hast@"^12.1.0" from remark-rehype@10.1.0
      node_modules/remark-rehype
        remark-rehype@"^10.1.0" from @nuxt/content@2.0.0
        node_modules/@nuxt/content
          @nuxt/content@"^2.0" from the root project
      mdast-util-to-hast@"^12.1.1" from @nuxt/content@2.0.0
      node_modules/@nuxt/content
        @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/mdast-util-to-hast/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from mdast-util-to-hast@12.1.1
  node_modules/mdast-util-to-hast
    mdast-util-to-hast@"^12.1.0" from remark-rehype@10.1.0
    node_modules/remark-rehype
      remark-rehype@"^10.1.0" from @nuxt/content@2.0.0
      node_modules/@nuxt/content
        @nuxt/content@"^2.0" from the root project
    mdast-util-to-hast@"^12.1.1" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/mdast-util-to-markdown/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from mdast-util-to-markdown@1.3.0
  node_modules/mdast-util-to-markdown
    mdast-util-to-markdown@"^1.0.0" from mdast-util-gfm@2.0.1
    node_modules/mdast-util-gfm
      mdast-util-gfm@"^2.0.0" from remark-gfm@3.0.1
      node_modules/remark-gfm
        remark-gfm@"^3.0.1" from @nuxt/content@2.0.0
        node_modules/@nuxt/content
          @nuxt/content@"^2.0" from the root project
    mdast-util-to-markdown@"^1.3.0" from mdast-util-gfm-footnote@1.0.1
    node_modules/mdast-util-gfm-footnote
      mdast-util-gfm-footnote@"^1.0.0" from mdast-util-gfm@2.0.1
      node_modules/mdast-util-gfm
        mdast-util-gfm@"^2.0.0" from remark-gfm@3.0.1
        node_modules/remark-gfm
          remark-gfm@"^3.0.1" from @nuxt/content@2.0.0
          node_modules/@nuxt/content
            @nuxt/content@"^2.0" from the root project
    mdast-util-to-markdown@"^1.3.0" from mdast-util-gfm-strikethrough@1.0.1
    node_modules/mdast-util-gfm-strikethrough
      mdast-util-gfm-strikethrough@"^1.0.0" from mdast-util-gfm@2.0.1
      node_modules/mdast-util-gfm
        mdast-util-gfm@"^2.0.0" from remark-gfm@3.0.1
        node_modules/remark-gfm
          remark-gfm@"^3.0.1" from @nuxt/content@2.0.0
          node_modules/@nuxt/content
            @nuxt/content@"^2.0" from the root project
    mdast-util-to-markdown@"^1.3.0" from mdast-util-gfm-table@1.0.4
    node_modules/mdast-util-gfm-table
      mdast-util-gfm-table@"^1.0.0" from mdast-util-gfm@2.0.1
      node_modules/mdast-util-gfm
        mdast-util-gfm@"^2.0.0" from remark-gfm@3.0.1
        node_modules/remark-gfm
          remark-gfm@"^3.0.1" from @nuxt/content@2.0.0
          node_modules/@nuxt/content
            @nuxt/content@"^2.0" from the root project
    mdast-util-to-markdown@"^1.3.0" from mdast-util-gfm-task-list-item@1.0.1
    node_modules/mdast-util-gfm-task-list-item
      mdast-util-gfm-task-list-item@"^1.0.0" from mdast-util-gfm@2.0.1
      node_modules/mdast-util-gfm
        mdast-util-gfm@"^2.0.0" from remark-gfm@3.0.1
        node_modules/remark-gfm
          remark-gfm@"^3.0.1" from @nuxt/content@2.0.0
          node_modules/@nuxt/content
            @nuxt/content@"^2.0" from the root project
    mdast-util-to-markdown@"^1.3.0" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/rehype-external-links/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from rehype-external-links@1.0.1
  node_modules/rehype-external-links
    rehype-external-links@"^1.0.1" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/rehype-sort-attribute-values/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from rehype-sort-attribute-values@4.0.0
  node_modules/rehype-sort-attribute-values
    rehype-sort-attribute-values@"^4.0.0" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/rehype-sort-attributes/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from rehype-sort-attributes@4.0.0
  node_modules/rehype-sort-attributes
    rehype-sort-attributes@"^4.0.0" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/rehype-slug/node_modules/unist-util-visit
  unist-util-visit@"^4.0.0" from rehype-slug@5.0.1
  node_modules/rehype-slug
    rehype-slug@"^5.0.1" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/remark-emoji/node_modules/unist-util-visit
  unist-util-visit@"^4.1.0" from remark-emoji@3.0.2
  node_modules/remark-emoji
    remark-emoji@"^3.0.2" from @nuxt/content@2.0.0
    node_modules/@nuxt/content
      @nuxt/content@"^2.0" from the root project

unist-util-visit@4.1.0
node_modules/@nuxt/content/node_modules/unist-util-visit
  unist-util-visit@"^4.1.0" from @nuxt/content@2.0.0
  node_modules/@nuxt/content
    @nuxt/content@"^2.0" from the root project

使わせてもらってる rehype-plugin たちが対応してないみたいなので抜いてみる

またモジュールが足りてない指摘も有るので追加対応もする

  • unified
  • unist-util-visit

これで npm run dev にて立ち上げ自体はできるようになった

tsconfig.json をスッキリさせた

{
+ "extends": "./.nuxt/tsconfig.json"
-  "compilerOptions": {
-    "target": "ES2018",
-    "module": "ESNext",
-    "moduleResolution": "Node",
-    "lib": [
-      "ESNext",
-      "ESNext.AsyncIterable",
-      "DOM"
-    ],
-    "esModuleInterop": true,
-    "allowJs": true,
-    "sourceMap": true,
-    "strict": true,
-    "noEmit": true,
-    "experimentalDecorators": true,
-    "baseUrl": ".",
-    "paths": {
-      "~/*": [
-        "./*"
-      ],
-      "@/*": [
-        "./*"
-      ]
-    },
-    "types": [
-      "@nuxt/types",
-      "@nuxt/content",
-      "@types/node"
-    ]
-  },
-  "exclude": [
-    "node_modules",
-    ".nuxt",
-    "dist"
-  ]
}

nuxt.config.ts にして一部精査

-const rehypePlugins = [
-  'rehype-plugin-auto-resolve-layout-shift',
-  'rehype-plugin-image-native-lazy-loading',
-]
+import { defineNuxtConfig } from 'nuxt'
 
-if (process.env.NODE_ENV === 'production') {
-  rehypePlugins.push([
-    'rehype-plugin-auto-resolve-layout-shift',
-    { type: 'maxWidth', maxWidth: 720 },
-  ])
-}
-
-export default {
+export default defineNuxtConfig({
   target: 'static',
   telemetry: false,
   head: {
@@ -33,18 +23,17 @@ export default {
     ],
   },
   css: ['modern-normalize', 'yama-normalize'],
-  buildModules: ['@nuxt/typescript-build'],
   modules: ['@nuxt/content'],
   content: {
-    markdown: {
-      remarkExternalLinks: {
-        target: '_blank',
-        rel: 'noopener noreferrer',
-      },
-      prism: {
-        theme: 'prism-themes/themes/prism-a11y-dark.css',
-      },
-      rehypePlugins,
+    highlight: {
+      theme: 'dark-plus'
     },
   },
-}
+  vue: {
+    config: {
+      compilerOptions: {
+        isCustomElement: (tag: string) => tag.startsWith('budoux-ja')
+      }
+    }
+  }
+});
  • highlight が指定しても効かない 🤔
  • vue config compilerOptions 周りも効かない 🤔

eslint 設定もアップデート

https://github.com/yamanoku/archives/pull/54/commits/9dd2353ab338b856facb906e0dd5db93cf4bf225

追加パッケージ

$ npm install -D typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser @nuxtjs/eslint-config-typescript

.eslintrc.js

   root: true,
   env: {
     browser: true,
-    node: true,
+    es2021: true,
+    node: true
   },
   extends: [
-    '@nuxtjs/eslint-config-typescript',
-    'plugin:prettier/recommended',
-    'plugin:nuxt/recommended',
+    'prettier',
+    'plugin:@typescript-eslint/recommended',
+    '@nuxtjs/eslint-config-typescript'
   ],
-  plugins: [],
-  // add your custom rules here
-  rules: {},
+  parserOptions: {
+    ecmaVersion: 'latest',
+    parser: '@typescript-eslint/parser',
+    sourceType: 'module'
+  },
+  plugins: ['vue', '@typescript-eslint']
 }

2.0.1 がリリースされてた

https://github.com/nuxt/content/releases/tag/2.0.1
- queryContent('/my-directory').sort({ createdAt: 0 })
+ queryContent('/my-directory').sort({ createdAt: -1 }) 

降順が -1 になったので変更

const { data: articles } = await useAsyncData('home', () =>
-  queryContent('/').sort({ date: 0 }).find()
+  queryContent('/').sort({ date: -1 }).find()
)

ページ遷移したときに位置がそのままになってしまう問題の対応

app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'

export default <RouterConfig>{
  scrollBehavior(to, from, savedPosition) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({ top: 0, left: 0 })
      }, 100)
    })
  },
}

smooth 付けるのは違和感あるなぁ…

この辺の設定をしてしまうとページ内のアンカーが一律同じ挙動(ページトップへ遷移)制御できなくなってしまう…

見出し内リンクマジでいらない…

このスクラップは2ヶ月前にクローズされました
ログインするとコメントできます