Skip to content

feat: add CI for publishing chrome extension #1568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Dec 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/odd-onions-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rrweb/web-extension": patch
---

fix: remove the permission not needed and update the player style link
18 changes: 14 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -33,7 +33,17 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

# - name: Send a Slack notification if a publish happens
# if: steps.changesets.outputs.published == 'true'
# # You can do something when a publish happens.
# run: my-slack-bot send-notification --message "A new version of ${GITHUB_REPOSITORY} was published!"
- name: Build Chrome Extension
if: steps.changesets.outputs.published == 'true'
run: NODE_OPTIONS='--max-old-space-size=4096' DISABLE_WORKER_INLINING=true yarn turbo run prepublish --filter=@rrweb/web-extension

- name: Publish Chrome Extension
uses: mnao305/[email protected]
if: steps.changesets.outputs.published == 'true'
with:
extension-id: 'pdaldeopoccdhlkabbkcjmecmmoninhe'
file-path: ./packages/web-extension/dist/chrome.zip
client-id: ${{ secrets.CWS_CLIENT_ID }}
client-secret: ${{ secrets.CWS_CLIENT_SECRET }}
refresh-token: ${{ secrets.CWS_REFRESH_TOKEN }}
publish: true
2 changes: 1 addition & 1 deletion packages/rrweb-player/package.json
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
"svelte": "^4.2.14",
"svelte-check": "^3.4.3",
"svelte-preprocess": "^5.0.3",
"svelte2tsx": "^0.7.6",
"svelte2tsx": "^0.7.30",
"tslib": "^2.0.0",
"vite": "^5.3.1"
},
3 changes: 3 additions & 0 deletions packages/web-extension/package.json
Original file line number Diff line number Diff line change
@@ -19,9 +19,12 @@
},
"devDependencies": {
"@rrweb/types": "^2.0.0-alpha.18",
"@types/chrome": "^0.0.287",
"@types/react-dom": "^18.0.6",
"@types/semver": "^7.5.8",
"@types/webextension-polyfill": "^0.9.1",
"@vitejs/plugin-react": "^4.2.1",
"semver": "^7.6.3",
"type-fest": "^2.19.0",
"vite": "^5.3.1",
"vite-plugin-web-extension": "^4.1.3",
6 changes: 2 additions & 4 deletions packages/web-extension/src/content/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Browser, { type Storage } from 'webextension-polyfill';
import Browser from 'webextension-polyfill';
import { nanoid } from 'nanoid';
import type { eventWithTime } from '@rrweb/types';
import {
@@ -166,9 +166,7 @@ async function initMainPage() {
async function initCrossOriginIframe() {
Browser.storage.local.onChanged.addListener((change) => {
if (change[LocalDataKey.recorderStatus]) {
const statusChange = change[
LocalDataKey.recorderStatus
] as Storage.StorageChange;
const statusChange = change[LocalDataKey.recorderStatus];
const newStatus =
statusChange.newValue as LocalData[LocalDataKey.recorderStatus];
if (newStatus.status === RecorderStatus.RECORDING) startRecord();
2 changes: 1 addition & 1 deletion packages/web-extension/src/manifest.json
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
"48": "icon48.png",
"128": "icon128.png"
},
"permissions": ["activeTab", "tabs", "storage", "unlimitedStorage"]
"permissions": ["activeTab", "storage", "unlimitedStorage"]
},
"v2": {
"common": {
7 changes: 5 additions & 2 deletions packages/web-extension/src/pages/Player.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// <reference types="chrome"/>
import { useRef, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import Replayer from 'rrweb-player';
@@ -29,9 +30,10 @@ export default function Player() {
.then((events) => {
if (!playerElRef.current) return;

const manifest = chrome.runtime.getManifest();
const rrwebPlayerVersion = manifest.version_name || manifest.version;
const linkEl = document.createElement('link');
linkEl.href =
'https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css';
linkEl.href = `https://cdn.jsdelivr.net/npm/rrweb-player@${rrwebPlayerVersion}/dist/style.min.css`;
linkEl.rel = 'stylesheet';
document.head.appendChild(linkEl);
playerRef.current = new Replayer({
@@ -46,6 +48,7 @@ export default function Player() {
console.error(err);
});
return () => {
// eslint-disable-next-line
playerRef.current?.pause();
};
}, [sessionId]);
19 changes: 12 additions & 7 deletions packages/web-extension/src/pages/index.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>rrweb</title>
<html>
<body>
<div id="root"></div>
</body>
<script type="module" src="./index.tsx"></script>
</html>

<head>
<meta charset="utf-8" />
<title>rrweb</title>
</head>

<body>
<div id="root"></div>
</body>
<script type="module" src="./index.tsx"></script>

</html>
31 changes: 28 additions & 3 deletions packages/web-extension/vite.config.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import zip from 'vite-plugin-zip-pack';
import * as path from 'path';
import type { PackageJson } from 'type-fest';
import react from '@vitejs/plugin-react';
import semver from 'semver';

const emptyOutDir = !process.argv.includes('--watch');

@@ -39,6 +40,29 @@ function useSpecialFormat(
};
}

/**
* Get the extension version based on the rrweb version.
*/
function getExtensionVersion(rrwebVersion: string): string {
const parsedVersion = semver.parse(rrwebVersion.replace('^', ''));

if (!parsedVersion) {
throw new Error('Invalid version format');
}

if (parsedVersion.prerelease.length > 0) {
// If it's a pre-release version like alpha or beta, strip the pre-release identifier
return `${parsedVersion.major}.${parsedVersion.minor}.${
parsedVersion.patch
}.${parsedVersion.prerelease[1] || 0}`;
} else if (rrwebVersion === '2.0.0') {
// This version has already been released as the first version. We need to add a patch version to it to avoid publishing conflicts.
return '2.0.0.100';
} else {
return rrwebVersion;
}
}

export default defineConfig({
root: 'src',
// Configure our outputs - nothing special, this is normal vite config
@@ -73,10 +97,11 @@ export default defineConfig({
const BrowserName =
process.env.TARGET_BROWSER === 'chrome' ? 'chrome' : 'firefox';
const commonManifest = originalManifest.common;
const rrwebVersion = packageJson.dependencies!.rrweb!.replace('^', '');
const manifest = {
version: '2.0.0',
version: getExtensionVersion(rrwebVersion),
author: packageJson.author,
version_name: packageJson.dependencies?.rrweb?.replace('^', ''),
version_name: rrwebVersion,
...commonManifest,
};
Object.assign(
@@ -92,7 +117,7 @@ export default defineConfig({
watchIgnored: ['*.md', '*.log'],
},
additionalInputs: ['pages/index.html', 'content/inject.ts'],
}),
}) as PluginOption,
// https://github.com/aklinker1/vite-plugin-web-extension/issues/50#issuecomment-1317922947
// transfer inject.ts to iife format to avoid error
useSpecialFormat(
2 changes: 1 addition & 1 deletion turbo.json
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
"vite.config.defaults.ts",
"tsconfig.json"
],
"globalPassThroughEnv": ["PUPPETEER_HEADLESS"],
"globalPassThroughEnv": ["PUPPETEER_HEADLESS", "DISABLE_WORKER_INLINING"],
"tasks": {
"prepublish": {
"dependsOn": ["^prepublish", "//#references:update"],
19 changes: 18 additions & 1 deletion vite.config.default.ts
Original file line number Diff line number Diff line change
@@ -2,13 +2,17 @@
import dts from 'vite-plugin-dts';
import { copyFileSync } from 'node:fs';
import { defineConfig, LibraryOptions, LibraryFormats, Plugin } from 'vite';
import glob from 'fast-glob';
import { build, Format } from 'esbuild';
import { resolve } from 'path';
import { umdWrapper } from 'esbuild-plugin-umd-wrapper';

// don't empty out dir if --watch flag is passed
const emptyOutDir = !process.argv.includes('--watch');
/**
* Chrome web store does not allow base64 inline workers.
* For chrome extension, we need to disable worker inlining to pass the review.
*/
const disableWorkerInlining = process.env.DISABLE_WORKER_INLINING === 'true';

function minifyAndUMDPlugin({
name,
@@ -157,6 +161,19 @@ export default function (
},
}),
minifyAndUMDPlugin({ name, outDir }),
{
name: 'remove-worker-inline',
enforce: 'pre',
transform(code, id) {
if (!disableWorkerInlining) return;
if (/\.(js|ts|jsx|tsx)$/.test(id)) {
return {
code: code.replace(/\?worker&inline/g, '?worker'),
map: null,
};
}
},
},
...plugins,
],
}));
42 changes: 40 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -2585,6 +2585,14 @@
dependencies:
"@babel/types" "^7.20.7"

"@types/chrome@^0.0.287":
version "0.0.287"
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.287.tgz#239969b1195b441836d2137125543b5241c41157"
integrity sha512-wWhBNPNXZHwycHKNYnexUcpSbrihVZu++0rdp6GEk5ZgAglenLx+RwdEouh6FrHS0XQiOxSd62yaujM1OoQlZQ==
dependencies:
"@types/filesystem" "*"
"@types/har-format" "*"

"@types/cookie@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
@@ -2622,6 +2630,18 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==

"@types/filesystem@*":
version "0.0.36"
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.36.tgz#7227c2d76bfed1b21819db310816c7821d303857"
integrity sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==
dependencies:
"@types/filewriter" "*"

"@types/filewriter@*":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.33.tgz#d9d611db9d9cd99ae4e458de420eeb64ad604ea8"
integrity sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==

"@types/[email protected]":
version "11.0.1"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.1.tgz#f542ec47810532a8a252127e6e105f487e0a6ea5"
@@ -2637,6 +2657,11 @@
dependencies:
"@types/node" "*"

"@types/har-format@*":
version "1.2.16"
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.16.tgz#b71ede8681400cc08b3685f061c31e416cf94944"
integrity sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==

"@types/http-cache-semantics@^4.0.2":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
@@ -2820,7 +2845,7 @@
"@types/prop-types" "*"
csstype "^3.0.2"

"@types/semver@^7.3.12", "@types/semver@^7.5.0":
"@types/semver@^7.3.12", "@types/semver@^7.5.0", "@types/semver@^7.5.8":
version "7.5.8"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
@@ -8985,6 +9010,11 @@ semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==

semver@^7.6.3:
version "7.6.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==

semver@~7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
@@ -9560,7 +9590,15 @@ svelte-preprocess@^5.0.3, svelte-preprocess@^5.1.3:
sorcery "^0.11.0"
strip-indent "^3.0.0"

svelte2tsx@^0.7.6, svelte2tsx@~0.7.0:
svelte2tsx@^0.7.30:
version "0.7.30"
resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.7.30.tgz#5dbd9e38c2fe54170b441409ebb2ee46c807be9e"
integrity sha512-sHXK/vw/sVJmFuPSq6zeKrtuZKvo0jJyEi8ybN0dfrqSYVvHu8zFbO0zQKAL8y/fYackYojH41EJGe6v8rd5fw==
dependencies:
dedent-js "^1.0.1"
pascal-case "^3.1.1"

svelte2tsx@~0.7.0:
version "0.7.9"
resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.7.9.tgz#a2b42e218e8808b9bd4b292dedba18ae8468abb0"
integrity sha512-Rm+0LAwg9wT4H2IsR8EaM9EWErTzi9LmuZKxkH5b1ua94XjQmwHstBP4VabLgA9AE6XmwBg+xK7Cjzwfm6ustQ==

Unchanged files with check annotations Beta

// should warn? maybe a text node isn't attached to a parent node yet?
return false;
} else {
el = dom.parentElement(node)!;

Check warning on line 285 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 285 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
}
try {
if (typeof maskTextClass === 'string') {
const recordInlineImage = () => {
image.removeEventListener('load', recordInlineImage);
try {
canvasService!.width = image.naturalWidth;

Check warning on line 705 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 705 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
canvasService!.height = image.naturalHeight;

Check warning on line 706 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 706 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
canvasCtx!.drawImage(image, 0, 0);

Check warning on line 707 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 707 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
attributes.rr_dataURL = canvasService!.toDataURL(

Check warning on line 708 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 708 in packages/rrweb-snapshot/src/snapshot.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
dataURLOptions.type,
dataURLOptions.quality,
);
* Browsers sometimes incorrectly escape `@import` on `.cssText` statements.
* This function tries to correct the escaping.
* more info: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259
* @param cssImportRule

Check warning on line 83 in packages/rrweb-snapshot/src/utils.ts

GitHub Actions / ESLint Check and Report Upload

tsdoc-param-tag-missing-hyphen: The @param block should be followed by a parameter name and then a hyphen

Check warning on line 83 in packages/rrweb-snapshot/src/utils.ts

GitHub Actions / ESLint Check and Report Upload

tsdoc-param-tag-missing-hyphen: The @param block should be followed by a parameter name and then a hyphen
* @returns `cssText` with browser inconsistencies fixed, or null if not applicable.
*/
export function escapeImportStatement(rule: CSSImportRule): string {
childNodes[i].textContent &&
typeof childNodes[i].textContent === 'string'
) {
const textContentNorm = normalizeCssString(childNodes[i].textContent!);

Check warning on line 475 in packages/rrweb-snapshot/src/utils.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 475 in packages/rrweb-snapshot/src/utils.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
for (let j = 3; j < textContentNorm.length; j++) {
// find a substring that appears only once
const bit = textContentNorm.substring(0, j);
plugins
?.filter((p) => p.observer)
?.map((p) => ({
observer: p.observer!,

Check warning on line 560 in packages/rrweb/src/record/index.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 560 in packages/rrweb/src/record/index.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
options: p.options,
callback: (payload: object) =>
wrappedEmit({
iframeManager.addLoadListener((iframeEl) => {
try {
handlers.push(observe(iframeEl.contentDocument!));

Check warning on line 578 in packages/rrweb/src/record/index.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion

Check warning on line 578 in packages/rrweb/src/record/index.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
} catch (error) {
// TODO: handle internal error
console.warn(error);
};
while (this.mapRemoves.length) {
this.mirror.removeNodeFromMap(this.mapRemoves.shift()!);

Check warning on line 366 in packages/rrweb/src/record/mutation.ts

GitHub Actions / ESLint Check and Report Upload

Forbidden non-null assertion
}
for (const n of this.movedSet) {
export type customElementCallback = (c: customElementParam) => void;
/**
* @deprecated

Check warning on line 612 in packages/types/src/index.ts

GitHub Actions / ESLint Check and Report Upload

tsdoc-missing-deprecation-message: The @deprecated block must include a deprecation message, e.g. describing the recommended alternative
*/
interface INode extends Node {
__sn: serializedNodeWithId;