Ymetrika update (#245)
* update claude with message about components * yandex metrika to ts * rm env * add .env example * use account from env * add tests
This commit is contained in:
1 parent
013578b518
commit
8c57976663
7 files changed
+60
-11
No files matched your search
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
APP_CARD_DEFAULT_IMAGE=https://art.shlisselburg.org/static/img/main.jpg
|
APP_CARD_DEFAULT_IMAGE=https://art.shlisselburg.org/static/img/main.jpg
|
||||||
|
NEXT_PUBLIC_YMETRIKA_ACCOUNT=XXX
|
||||||
@@ -21,3 +21,4 @@ dist
|
|||||||
.vercel
|
.vercel
|
||||||
.next
|
.next
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
|
.env
|
||||||
@@ -26,6 +26,18 @@ Feature branches are named `issue-XXX` where `XXX` is the related GitHub issue n
|
|||||||
|
|
||||||
ESLint 9 flat config (`eslint.config.js`) using `FlatCompat` from `@eslint/eslintrc` to bridge `eslint-config-next` (which doesn't support native flat config in Next.js 15.x). Extends `next/core-web-vitals`. Enforces: no semicolons, double quotes, 4-space indentation, always-multiline trailing commas, `eol-last`.
|
ESLint 9 flat config (`eslint.config.js`) using `FlatCompat` from `@eslint/eslintrc` to bridge `eslint-config-next` (which doesn't support native flat config in Next.js 15.x). Extends `next/core-web-vitals`. Enforces: no semicolons, double quotes, 4-space indentation, always-multiline trailing commas, `eol-last`.
|
||||||
|
|
||||||
|
**React components:** Use regular function declarations (not arrow functions) and `type` for props. Do not use `React.FC`.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export type MyComponentProps = {
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MyComponent({ value }: MyComponentProps) {
|
||||||
|
return <div>{value}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
**Pages Router with SSG/ISR:** All pages use `getStaticProps`/`getStaticPaths` with 30-second revalidation. The catch-all route `pages/[...slug].tsx` handles all dynamic content pages.
|
**Pages Router with SSG/ISR:** All pages use `getStaticProps`/`getStaticPaths` with 30-second revalidation. The catch-all route `pages/[...slug].tsx` handles all dynamic content pages.
|
||||||
|
|||||||
+4
-2
@@ -7,7 +7,7 @@ import "src/style/kazimir/video.css"
|
|||||||
import App from "next/app"
|
import App from "next/app"
|
||||||
import Head from "next/head"
|
import Head from "next/head"
|
||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
import { YMetrika } from "src/components/YMetrika"
|
import { YMetrika } from "@/components/YMetrika"
|
||||||
import { ThemeColor } from "@/ui/ThemeColor"
|
import { ThemeColor } from "@/ui/ThemeColor"
|
||||||
|
|
||||||
export default class MyApp extends App {
|
export default class MyApp extends App {
|
||||||
@@ -41,7 +41,9 @@ export default class MyApp extends App {
|
|||||||
href="/feed.xml"
|
href="/feed.xml"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<YMetrika account={24027460} />
|
{process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT && (
|
||||||
|
<YMetrika account={Number(process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT)} />
|
||||||
|
)}
|
||||||
|
|
||||||
<ThemeColor
|
<ThemeColor
|
||||||
color="white"
|
color="white"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { describe, it, expect } from "vitest"
|
||||||
|
import { script } from "./YMetrika"
|
||||||
|
|
||||||
|
describe("YMetrika script", () => {
|
||||||
|
it("should embed account id into metrika counter variable", () => {
|
||||||
|
const result = script(99999)
|
||||||
|
expect(result).toContain("w.yaCounter99999")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should embed account id into metrika config", () => {
|
||||||
|
const result = script(99999)
|
||||||
|
expect(result).toContain("id:99999")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should include metrika watch.js script url", () => {
|
||||||
|
const result = script(99999)
|
||||||
|
expect(result).toContain("https://mc.yandex.ru/metrika/watch.js")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should use yandex_metrika_callbacks", () => {
|
||||||
|
const result = script(99999)
|
||||||
|
expect(result).toContain("yandex_metrika_callbacks")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should produce different output for different accounts", () => {
|
||||||
|
const a = script(11111)
|
||||||
|
const b = script(22222)
|
||||||
|
expect(a).toContain("yaCounter11111")
|
||||||
|
expect(b).toContain("yaCounter22222")
|
||||||
|
expect(a).not.toContain("yaCounter22222")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import React from "react"
|
export type YMetrikaProps = {
|
||||||
|
account: number
|
||||||
|
}
|
||||||
|
|
||||||
function script(account) {
|
export function script(account: number) {
|
||||||
return `
|
return `
|
||||||
(function (d, w, c) {
|
(function (d, w, c) {
|
||||||
(w[c] = w[c] || []).push(function() {
|
(w[c] = w[c] || []).push(function() {
|
||||||
@@ -14,14 +16,14 @@ function script(account) {
|
|||||||
});
|
});
|
||||||
} catch(e) { }
|
} catch(e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
var n = d.getElementsByTagName("script")[0],
|
var n = d.getElementsByTagName("script")[0],
|
||||||
s = d.createElement("script"),
|
s = d.createElement("script"),
|
||||||
f = function () { n.parentNode.insertBefore(s, n); };
|
f = function () { n.parentNode.insertBefore(s, n); };
|
||||||
s.type = "text/javascript";
|
s.type = "text/javascript";
|
||||||
s.async = true;
|
s.async = true;
|
||||||
s.src = "https://mc.yandex.ru/metrika/watch.js";
|
s.src = "https://mc.yandex.ru/metrika/watch.js";
|
||||||
|
|
||||||
if (w.opera == "[object Opera]") {
|
if (w.opera == "[object Opera]") {
|
||||||
d.addEventListener("DOMContentLoaded", f, false);
|
d.addEventListener("DOMContentLoaded", f, false);
|
||||||
} else { f(); }
|
} else { f(); }
|
||||||
@@ -29,6 +31,6 @@ function script(account) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const YMetrika = (props) => (
|
export function YMetrika({ account }: YMetrikaProps) {
|
||||||
<script dangerouslySetInnerHTML={{ __html: script(props.account) }} />
|
return <script dangerouslySetInnerHTML={{ __html: script(account) }} />
|
||||||
)
|
}
|
||||||
+1
-1
@@ -9,6 +9,6 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
include: ["src/**/*.test.ts"],
|
include: ["src/**/*.test.{ts,tsx}"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Reference in new issue
Block a user