reviewdog/stylelintが動かない

  • このエントリーをはてなブックマークに追加

reviewdog便利です。
stylelint用のactionがあるので、設定してみたのですがStylelintでひっかかるコードをPushしても報告してくれません。

該当コードは以下のようになっています。

entrypoint.sh
if [ "${INPUT_REPORTER}" == 'github-pr-review' ]; then
# Use jq and github-pr-review reporter to format result to include link to rule page.
$(npm bin)/stylelint "${INPUT_STYLELINT_INPUT:-'**/*.css'}" --config="${INPUT_STYLELINT_CONFIG}" --ignore-pattern="${INPUT_STYLELINT_IGNORE}" -f json \
| jq -r '.[] | {source: .source, warnings:.warnings[]} | "\(.source):\(.warnings.line):\(.warnings.column):\(.warnings.severity): \(.warnings.text) [\(.warnings.rule)](https://stylelint.io/user-guide/rules/\(.warnings.rule))"' \
| reviewdog -efm="%f:%l:%c:%t%*[^:]: %m" -name="${INPUT_NAME:-stylelint}" -reporter=github-pr-review -level="${INPUT_LEVEL}" -filter-mode="${INPUT_FILTER_MODE}" -fail-on-error="${INPUT_FAIL_ON_ERROR}"
else
$(npm bin)/stylelint "${INPUT_STYLELINT_INPUT:-'**/*.css'}" --config="${INPUT_STYLELINT_CONFIG}" --ignore-pattern="${INPUT_STYLELINT_IGNORE}" \
| reviewdog -f="stylelint" -name="${INPUT_NAME:-stylelint}" -reporter="${INPUT_REPORTER:-github-pr-check}" -level="${INPUT_LEVEL}" -filter-mode="${INPUT_FILTER_MODE}" -fail-on-error="${INPUT_FAIL_ON_ERROR}"
fi

reporterにgithub-pr-reviewを設定した場合は動きますが、このモードはBotがレビュワーに入ってくるやつなのでgithub-or-checkを使いたい。そうすると、elseの方が実行されるわけですが、stylelintの結果をreviewdog -f=stylelint につなげても何も出力されません。
debugのためにteeオプションを付けると元の出力は表示されるので、Stylelint自体は動作しています。もしreviewdogも正しく処理されれば二重で表示されます。

npx stylelint "**/*.css" | reviewdog -f=stylelint -reporter=local -level=error -filter-mode=nofilter --tee

結論から言えば、--no-colorを指定する必要がありました。が、今のバージョンでは--no-colorを指定することができません。

npx stylelint "**/*.css" --no-color | reviewdog -f=stylelint -reporter=local -level=error -filter-mode=nofilter --tee

なので、このActionを使わずに、自分でLintを実行し、reviewdogにつなげる必要があります。

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: npm
cache-dependency-path: |
package-lock.json
- run: npm ci
- uses: reviewdog/action-setup@v1
- run: reviewdog -version
- name: stylelint
env:
# reviewdogはこの環境変数でTokenを参照する
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npx stylelint "**/*.css" --no-color \
| reviewdog -f="stylelint" -name="stylelint" -reporter="github-pr-check" -level="error" -filter-mode="nofilter" -fail-on-error="false"

これでreviewdogがannotationを付けたりと正しく報告してくれるようになりました。
※reviewdogのオプションは必要に応じて変更してください。

参考情報

Vue3でaxiosをMock化する

  • このエントリーをはてなブックマークに追加

APIのアクセスはaxiosでコールするけど、開発中はMockに差し替えるということをします。

mockにはaxios-mock-adapterを利用します。

mock.js
import MockAdapter from 'axios-mock-adapter'
const data = { world: "world" }
export default {
run(client) {
const mock = new MockAdapter(client, {delayResponse: 300})
mock.onGet("/api/hello").reply(200, data)
}
}

delayResponseを設定することで意図的に遅くすることができます。

mockの色々な書き方

直接JSONを返す

mock.onGet("/api/hello").reply(200, { hello: "world" })

関数の実行

mock.onGet("/api/hello").reply((config) => {
return [200, { hello: "world" }];
});

Queryの処理

ややこしいのは、config.paramsではないと言うことです。
/api/hello?name=taroとリクエストする場合は、正規表現で/\/api\/hello\?.*/と指定する必要があります。ここは良い感じに処理して欲しいですね…。なので、

function parseQueryString(url) {
const queryString = url.replace(/.*\?/, '')

const result = {}
if (queryString === url || !queryString) {
return result
}

const urlParams = new URLSearchParams(queryString)
urlParams.forEach((val, key) => {
if (Object.prototype.hasOwnProperty.call(result, key)) {
result[key] = [result[key], val]
} else {
result[key] = val
}
});

return result
}

mock.onGet(/\/api\/hello2?.*/).reply((config) => {
const params = parseQueryString(config.url)
return [200, { config, params }]
})

postされた内容を見る。FormDataの場合。

const formData = new FormData();
formData.append("name", "taro");
formData.append("flag1", "true");
const resp = await $client.post("/api/formPost", formData, {});
mock.onPost("/api/post").reply(config => {
const formData = config.data
const name = formData.get("name")
...
})

PostされたJSONを見る

const resp = await $client.post("/api/postJson", {
name: "hello",
message: "world",
});

config.dataは文字列なのでJSON.parseする。

mock.onPost("/api/postJson").reply((config) => {
const data = JSON.parse(config.data);
return [200, { data }];
});

わざとDelayさせる

delayResponseの全体設定とは別に、個別にDelayさせる。
Promiseを返して、setTimeoutが終わった時にresolveする。

mock.onGet("/api/delayHello").reply((config) => {
const delay = 5000;
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200, { hello: "world" }]);
}, delay);
});
});

関連記事

参考情報

Vue3でGlobalなFiltersの実現

  • このエントリーをはてなブックマークに追加

Vue3+CompositionAPIを使っていますが、MixinやFilterが無くなったのでその代替をどうするか。

Filterの代わり

globalPropertiesを使います。
globalPropertiesに登録したものは、Templateからそのまま参照できます。

main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
formatNumber(number) {
return Number(number).toLocaleString("en-US", {
maximumFractionDigits: 20
})
}
};
app.mount("#app")
template
{{ $filters.formatNumber(num) }}

setup()からの参照

setup()内では$filtersでは参照できません。参照したい場合は、次のようにgetCurrentInstance()を利用します。

import { defineComponent, getCurrentInstance } from "vue"
export default defineComponent({
setup() {
const app = getCurrentInstance()
const $filters = app.appContext.config.globalProperties.$filters
}
})

sample-code: https://codesandbox.io/s/upbeat-mcnulty-mxi7i?file=/src/App.vue

provide/ inject

もしくは、設計思想的にはprovide, injectを利用するのがよさそうです。

main.js
app.provide("$filters", app.config.globalProperties.$filters)
setup() {
const $filters = inject("$filters")
}

キーは文字列じゃなくて、exportしたSymbolにするのが良さそう。

参考情報

HexoでNodeのバージョンを上げたらWarningが出るようになった

  • このエントリーをはてなブックマークに追加

Hexoが利用しているNodeのバージョンを12.16.1から16.5.0にあげたら次の警告が出るようになった。
Hexoのバージョンは5.4.0です。

(node:6910) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:6910) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:6910) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
(node:6910) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(node:6910) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:6910) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency

--trace-warningsを付けて実行したところ、次の結果が得られた。どうやら、Stylusがよろしくないらしい。

(node:2398) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:42:23)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:57:16)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
(node:2398) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:43:23)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:57:16)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
(node:2398) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:44:25)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:57:16)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
(node:2398) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:42:23)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:58:17)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
(node:2398) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:43:23)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:58:17)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
(node:2398) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
at emitCircularRequireWarning (node:internal/modules/cjs/loader:701:11)
at Object.get (node:internal/modules/cjs/loader:715:5)
at Boolean.Node [as constructor] (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/node.js:44:25)
at new Boolean (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/boolean.js:23:8)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/nodes/index.js:58:17)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/mnt/wsl/git-repos/github.com/tamtam180/tamtam180.github.io/blog/node_modules/nib/node_modules/stylus/lib/lexer.js:13:13)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)

依存関係

依存関係を調べます。Hexoのpackage.jsonは次のようになっています。

package.json
{
"name": "hexo-site",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"server": "hexo server"
},
"hexo": {
"version": "5.4.0"
},
"dependencies": {
"hexo": "^5.4.0",
"hexo-deployer-git": "^3.0.0",
"hexo-generator-archive": "^1.0.0",
"hexo-generator-category": "^1.0.0",
"hexo-generator-feed": "^3.0.0",
"hexo-generator-index": "^2.0.0",
"hexo-generator-search": "^2.4.0",
"hexo-generator-sitemap": "^2.0.0",
"hexo-generator-tag": "^1.0.0",
"hexo-related-popular-posts": "^5.0.1",
"hexo-renderer-ejs": "^1.0.0",
"hexo-renderer-marked": "git+https://github.com/tamtam180/hexo-renderer-marked.git#feature/use-class-table-align",
"hexo-renderer-stylus": "^2.0.1",
"hexo-server": "^2.0.0"
}
}

hexo-renderer-stylusstylus@0.54.8を利用していますが、nibの現時点での最新バージョンである1.1.2では古いStylus0.54.5を見ています。これが良くない。nibのmasterブランチを見ると、このコミット0.54.8を使うようになっていますが、このリビジョンが取り込まれているバージョンはまだリリースされていません。

"hexo-renderer-stylus": "^2.0.1"
"nib": "^1.1.2"
"stylus": "^0.54.5" # これが問題
"stylus": "^0.54.8"

ワークアラウンド

package-lock.jsonで解決されたバージョンを直接弄ってしまい、nibが新しいバージョンのStylusを参照するようにすることで回避できます。

参考情報

nodejsのsemverまとめ

  • このエントリーをはてなブックマークに追加

semverの解釈がエコシステムによって異なったりする場合があるので、nodejs(npm)の場合を備忘録メモ。

3桁の数字で表現:x.y.z

  • 最初の桁はメジャーバージョン
  • 2桁目はマイナーバージョン
  • 3桁目はパッチバージョン

バージョンの上げ方

  • 互換性のないAPIを変更する場合、メジャーバージョンをアップ
  • 下位互換性のある方法で機能を追加する場合、マイナーバージョンをアップ
  • 下位互換性のあるバグ修正を行う場合、パッチバージョンがアップ

バージョン表記の記号

  • ^: 一番左にあるゼロ以外の数値を変更しない

    • ^1.2.3 => 1.2.3 <= version < 2.0.0
    • ^0.13.0 => 0.13.0 <= version < 0.14.0
    • 0.xの場合とそれ以外とでルールが異なるので注意。
  • ~: 一番右のバージョンがあがる

    • ~1.2.3 => 1.2.3 <= version < 1.3.0
    • ~1.2 => 1.2.0 <= version < 1.3.0, 1.2.xと同じ。
    • ~1 => 1 <= version < 2, 1.xと同じ。
  • = ピンポイントでそのバージョン

    • =1.2.3 => 1.2.3
  • - レンジ

    • 1.2.3 - 1.2.4 => 1.2.3 <= version <=1.2.4
    • 両端とも含みます
  • .xという表記もできるようだ

その他

  • 記号なしの場合は、ピンポイントでそのバージョン。(=と同じかな)
  • latest 最新のバージョン。(正確にはTag指定で、npmレポジトリにlatestというタグが存在するから)

複数指定

ルールが分かりづらい場合、分解して書いた方が分かりやすい

  • 1.2.3 - 1.2.5
  • >=1.2.3 <1.3.0
  • <1.0.0 || >2.3.4 || >=3.0.0 <4.0.0

確認する方法

npm semver calculator というツールでオンラインで検証できます。

参考情報

package.jsonでgithubを直接参照する

  • このエントリーをはてなブックマークに追加

通常は、semverを指定していますが、npmのtag, 他にもhttp(s)から始まるURL、GitのURLや、GithubのProject/Repo、Localファイルのパスを指定することができます。

package.json
{
"dependencies": {
"hexo-renderer-ejs": "^1.0.0",
"hexo-renderer-marked": "git+https://github.com/tamtam180/hexo-renderer-marked.git#feature/use-class-table-align"
}
}

npmのtag

"example1": "latest"
"example2": "next"

URL

"example": "http://example.com/"

Git Url

"example1": "git+https://github.com/tamtam180/hexo-renderer-marked.git#feature/use-class-table-align"
"example2": "git+ssh://github.com/tamtam180/hexo-renderer-marked.git#feature/use-class-table-align"

#でブランチやHash指定が可能。

git+ssh://git@github.com:npm/cli.git#v1.0.27
git+ssh://git@github.com:npm/cli#semver:^5.0
git+https://isaacs@github.com/npm/cli.git
git://github.com/npm/cli.git#v1.0.27

Github Url

"example1": "tamtam180/hexo-renderer-marked.git#feature\/use-class-table-align"

ブランチのスラッシュはエスケープが必要?

Localファイル

サンプル
../foo/bar
~/foo/bar
./foo/bar
/foo/bar

参考情報

ESLintのno-unused-varsを特定の箇所だけ無効にしたい

  • このエントリーをはてなブックマークに追加

例えば次のようなクラスを定義したい場合、processcontextが未使用なのでESLintにno-unused-varsの警告を受けます。このルールを部分的に無効にする方法にはいくつかあります。

Base
class Base {
constructor() {
}
execute() {
const context = {}
this.process(context)
}
// eslint-disable-next-line no-unused-vars
process(context) {
// override
}
}

特定の次の行を無効にする

eslint-disable-next-line

// eslint-disable-next-line no-unused-vars
const myVars = 1;

同じ行を無効にする

eslint-disable-line

const myVars = 1; // eslint-disable-line no-unused-vars

範囲を無効にする

/* eslint-disable no-unused-vars */
const myVars1 = 1;
const myVars2 = 1;
const myVars3 = 1;
/* eslint-enable no-unused-vars */

ファイル全体を対象に無効にする

ファイルの先頭に次のブロックコメントを記載します。

/* eslint no-unused-vars: 0 */

注意点として、/**/のコメント記法を利用することです。
また、指定している数字は、0=”off”, 1=”warn”, 2=”error”の意味です。

参考

ファイルをドロップする要素が子要素を持っているとDragLeaveが発生してしまう

  • このエントリーをはてなブックマークに追加

Drag and Dropを実装する時に、ドロップする要素が子要素を持っていると、DragLeaveが発生してしまう。
子要素(別要素)にEnterしたということは、対象の要素がLeaveしたということになるらしいです。

対策の方法は色々とありますが、カウンタを用意するのが一番簡単です。
ひとまず、Vue3+CompositionAPIでサンプルを。

template
<div :class="{enter: ddCounter>0}"
@dragenter="fileDragEnter"
@dragleave="fileDragLeave"
@dragover.prevent
@drop.prevent="fileDrop"
>
</div>
script
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const ddCounter = ref(0)
const fileDragEnter = () => { ddCounter.value++ }
const fileDragLeave = () => { ddCounter.value-- }
const fileDrop = (event) => {
ddCounter.value = 0
}
return {
ddCounter,
fileDragEnter,
fileDragLeave,
fileDrop,
}
}
})
style
.enter {
border: 5px dotted powderblue;
}

サンプルコード ▶ Vue SFC Playground

参考

MySQLのJSONからboolean型のGenerated Columnを定義する時の注意点

  • このエントリーをはてなブックマークに追加

確認したバージョンは、MySQL8.0.25。
JSONのtrue/falseを参照してMySQLのboolean(tinyint)にする時、ついうっかりvarchar等と同じ感覚でjson_unquoteをするとエラーになる。

テスト用の定義

create table test1 (
id bigint not null,
data json not null,
name varchar(32) as (json_unquote(data->'$.name')) stored,
flag1 boolean as (json_unquote(data->'$.flag1')) stored, -- ※間違い
flag2 boolean as ((data->'$.flag2')) stored,
constraint pk_test1 primary key(id)
);

間違い

insert into test1 set id = 1, data = '{"name":"hello", "flag1": true, "flag2": true}';

flag1列でエラー。boolean列にjson_unquoteしているから。

ERROR 1366 (HY000): Incorrect integer value: 'true' for column 'flag1' at row 1

正しい

flag2はjson_unquoteをしていないので成功する。

insert into test1 set id = 1, data = '{"name":"hello", "flag2": true}';
insert into test1 set id = 2, data = '{"name":"hello", "flag2": false}';
select * from test1;
+----+-----------------------------------+-------+-------+-------+
| id | data | name | flag1 | flag2 |
+----+-----------------------------------+-------+-------+-------+
| 1 | {"name": "hello", "flag2": true} | hello | NULL | 1 |
| 2 | {"name": "hello", "flag2": false} | hello | NULL | 0 |
+----+-----------------------------------+-------+-------+-------+

型は何になっている??

MySQLにはpg_typeofみたいなものはないので、Selectの結果でTEMPテーブルを作って確認します。

create temporary table tmp1
select
(json_extract('{"name":"hello", "flag1": true}', '$.flag1')) as c1,
(json_unquote(json_extract('{"name":"hello", "flag1": true}', '$.flag1'))) as c2
;

desc tmp1;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| c1 | json | YES | | NULL | NULL |
| c2 | longtext | YES | | NULL | NULL |
+-------+----------+------+-----+---------+-------+

select * from tmp1;
+------+------+
| c1 | c2 |
+------+------+
| true | true |
+------+------+

json_unquoteしたものはlongtextのようです。
つまり、jsonからtinyintへの変換は成功するが、longtextからtinyintへの変換は失敗するということになります。

確認してみます。

select cast(json_extract('{"name":"hello", "flag1": true}', '$.flag1') as signed) as x;
+------+
| x |
+------+
| 1 |
+------+
1 row in set (0.00 sec)

対して、

select cast(json_unquote(json_extract('{"name":"hello", "flag1": false}', '$.flag1')) as signed) as x;
+------+
| x |
+------+
| 0 |
+------+
1 row in set, 1 warning (0.00 sec)

駄目な上に警告がでています。

 show warnings;
+---------+------+--------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------+
| Warning | 1292 | Truncated incorrect INTEGER value: 'false' |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

検証の単純化

-- OK
select cast(true as signed);
select cast(cast('true' as json) as signed);

-- NG
select cast('true' as signed)

そんなわけで、JSONのbooleanを扱うときは、気をつけましょうということで。

MySQL8でOut of sort memoryが発生するようになった

  • このエントリーをはてなブックマークに追加

MySQL8.0.21から8.0.25にアップグレードした後、次のような単純なクエリを発行したらERROR 1038 (HY001): Out of sort memory, consider increasing server sort buffer sizeが発生するようになった。

SELECT *
FROM hoge_table
ORDER BY created_at DESC LIMIT 10

このテーブルは次のように、JSONカラムとそれを参照する大量のGeneratedカラムを持つテーブルです。

create table hoge_table(
id varchar(32) ascii not null,
data json not null,
c1 varchar(256) as (json_unquote(data->'$.c1')) stored,
c2 varchar(256) as (json_unquote(data->'$.c2')) stored,
c3 varchar(256) as (json_unquote(data->'$.c3')) stored,
.... 20カラムくらい,
constraint pk_hoge_table primary key (id)
) default charset utf8mb4 row_format=compressed key_block_size=4;

Bug Ticket:103225に情報があります。

対策

sort_buffer_sizeが256KBなので1Mに増やしました。innodb_sort_buffer_sizeではなくsort_buffer_sizeです。私は幸いにして、これで回避できました。

オンラインで変更

set global sort_buffer_size = 1*1024*1024;
# 変わらない場合は..
set @@sort_buffer_size = 1*1024*1024;

show variables like '%sort%';
/etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
sort_buffer_size = 1M

参考