Skip to content
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

fix(analytics): sanitize filenames [MA-1651] #366

Merged
merged 7 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
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
49 changes: 43 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ Monorepo for **open-source** Kong UI components and utilities.
- [ESLint](#eslint)
- [Type Checking](#type-checking)
- [Testing](#testing)
- [File naming convensions](#file-naming-convensions)
- [Preview sandbox build](#preview-sandbox-build)
- [Build for production](#build-for-production)
- [Committing Changes](#committing-changes)
- [Enforcing Commit Format](#enforcing-commit-format)
- [Generating type interface documentation](#generating-type-interface-documentation)
- [Preview components](#preview-components)
- [Running consuming application with local copy of the package](#running-consuming-application-with-local-copy-of-the-package)
- [Preview components](#preview-components)
- [Running consuming application with local copy of the package](#running-consuming-application-with-local-copy-of-the-package)
- [Host App Troubleshooting](#host-app-troubleshooting)
- [Analytics Packages are blocked by some ad-blockers](#analytics-packages-are-blocked-by-some-ad-blockers)

## What goes here

Expand Down Expand Up @@ -182,7 +182,7 @@ If your package generates **types**, then add a `build:docs` script to your `pac

Please run the `build:docs` command manually to generate the docs and then commit them to your PR.

## Preview components
### Preview components

You are working on the PR and changing component project. Let's say `@kong-ui-public/i18n`. You want to try to deploy consuming application (`khcp-ui` for example) that uses your changed code without merging your changes to main and publishing new version of `@kong-ui-public/i18n`. Here are the steps:

Expand All @@ -202,7 +202,7 @@ Install the preview version of the package in consuming application, let that PR

_Never merge consuming application code that uses preview version of the package. PR versions will be deprecated and unpublished when your PR is closed._

## Running consuming application with local copy of the package
### Running consuming application with local copy of the package

You are developing shared component (let's say `@kong-ui-public/forms`) and you need to run consuming application with the current version of the code you have locally in your `public-ui-components/packages/{workspace}/forms` branch. Here is how to do it:

Expand Down Expand Up @@ -266,3 +266,40 @@ In some cases HMR (hot module reloading) is not working out of the box in this c
yarn install --force --frozen-lockfile
```

## Host App Troubleshooting

### Analytics Packages are blocked by some ad-blockers

Some ad blockers inadvertently block build files with the string `analytics` in the name. As a proactive measure, the `vite.config.ts` files in our packages utilize a `sanitizePackageName` utility that replaces instances of the string `analytics` with `vitals` in generated filenames and global variables.

If your host application _still_ has issues with ad blockers, you can try adding `build` rules to your host application's `vite.config.js` (or similar) to replace instances of the strings in components and packages:

```ts
// vite.config.ts
import { defineConfig } from 'vite'

// Replace any variation of string 'Analytics' in assets and chunks. Replacements are in order to preserve capitalization.
// The third replacement is a catch-all in case a string like `ANALYTICS` is present
const replaceAnalytics = (str: string) => str.replace(/Analytics/g, 'Vitals').replace(/analytics/gi, 'vitals')

export default defineConfig({
// ...
build: {
rollupOptions: {
output: {
chunkFileNames: (chunkInfo) => {
const name = replaceAnalytics(chunkInfo.name || '')

return `${name}.[hash].js`
},
assetFileNames: (assetInfo) => {
// Replace any instances of `analytics` in the external package name
const filename = replaceAnalytics(assetInfo.name || '').split('.')[0]

return `assets/${filename}.[hash].[ext]`
},
},
},
},
})
```
6 changes: 3 additions & 3 deletions packages/analytics/analytics-utilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ Commonly used types, interfaces and utils used with Kong analytics.

## Features

- Common types, interfaces and utils for Kong analytics
- Common types, interfaces and utilities for Kong analytics

## Usage

- Install and import/use types and utils as needed
- Install and import/use types and utilities as needed

### Install

```sh
yarn add @kong-ui-public/analytics-utilities
yarn add @kong-ui-public/analytics-utilities
```

### TypeScript interfaces
Expand Down
8 changes: 4 additions & 4 deletions packages/analytics/analytics-utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
"name": "@kong-ui-public/analytics-utilities",
"version": "0.1.1",
"type": "module",
"main": "./dist/analytics-utilities.umd.js",
"module": "./dist/analytics-utilities.es.js",
"main": "./dist/vitals-utilities.umd.js",
"module": "./dist/vitals-utilities.es.js",
"types": "dist/types/index.d.ts",
"files": [
"dist"
],
"exports": {
".": {
"import": "./dist/analytics-utilities.es.js",
"require": "./dist/analytics-utilities.umd.js"
"import": "./dist/vitals-utilities.es.js",
"require": "./dist/vitals-utilities.umd.js"
},
"./package.json": "./package.json",
"./dist/*": "./dist/*"
Expand Down
7 changes: 4 additions & 3 deletions packages/analytics/analytics-utilities/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'analytics-utilities'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
test: {
Expand Down
7 changes: 4 additions & 3 deletions packages/analytics/metric-cards/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'metric-cards'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
7 changes: 4 additions & 3 deletions packages/core/app-layout/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'app-layout'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
8 changes: 4 additions & 4 deletions packages/core/cli/src/__template__/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
"name": "@kong-ui-public/{%%PACKAGE_NAME%%}",
"version": "0.0.1",
"type": "module",
"main": "./dist/{%%PACKAGE_NAME%%}.umd.js",
"module": "./dist/{%%PACKAGE_NAME%%}.es.js",
"main": "./dist/{%%SANITIZED_PACKAGE_NAME%%}.umd.js",
"module": "./dist/{%%SANITIZED_PACKAGE_NAME%%}.es.js",
"types": "dist/types/index.d.ts",
"files": [
"dist"
],
"exports": {
".": {
"import": "./dist/{%%PACKAGE_NAME%%}.es.js",
"require": "./dist/{%%PACKAGE_NAME%%}.umd.js"
"import": "./dist/{%%SANITIZED_PACKAGE_NAME%%}.es.js",
"require": "./dist/{%%SANITIZED_PACKAGE_NAME%%}.umd.js"
},
"./package.json": "./package.json",
"./dist/*": "./dist/*"
Expand Down
7 changes: 4 additions & 3 deletions packages/core/cli/src/__template__/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = '{%%PACKAGE_NAME%%}'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
21 changes: 21 additions & 0 deletions packages/core/cli/src/core/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ import questions from '../questions'

const { workspaceName, packageName, confirmPackageName } = questions

/**
* Sanitize package/filename to exclude undesired strings
* IMPORANT: If this function is changed, you **must** change the function in `/vite.config.shared.ts` as well.
* @param {string} packageName The string to sanitize
* @returns {string} The sanitized package/filename string
*/
export const sanitizePackageName = (packageName: string): string => {
// Add additional replace rules as needed

// Replace any variation of string 'Analytics' in assets and chunks. These are in order to preserve capitalization.
// (Some adblock filter lists deny requests for files starting with "assets/analytics". See MA-926 for more context.)
const sanitizedName = (packageName || '').replace(/Analytics/g, 'Vitals').replace(/analytics/gi, 'vitals')

return sanitizedName
}

/**
* @description Create new files for package
* @param {string} workspace Workspace name
Expand Down Expand Up @@ -53,6 +69,9 @@ const createPackageFiles = async (workspace: string, packageName: string): Promi
const filenamePath = filename.split('__template__/')
const relativePath = filenamePath[1]
const newFilePath = `${packagePath(workspace, packageName)}/${relativePath.replace(/Template/g, componentName)}`
// Replace any variation of string 'Analytics' in assets and chunks. These are in order to preserve capitalization.
// (Some adblock filter lists deny requests for files starting with "assets/analytics". See MA-926 for more context.)
const sanitizedPackageName = sanitizePackageName(packageName)

// If template files exist
if (stats.isFile()) {
Expand All @@ -64,6 +83,8 @@ const createPackageFiles = async (workspace: string, packageName: string): Promi
// Replace template strings
const fileContent = fs.readFileSync(filename, 'utf8')
.replace(/{%%PACKAGE_NAME%%}/g, packageName)
// The SANITIZED_PACKAGE_NAME replaces `analytics` with `vitals`
.replace(/{%%SANITIZED_PACKAGE_NAME%%}/g, sanitizedPackageName)
.replace(/{%%COMPONENT_NAME%%}/g, componentName)
.replace(/{%%WORKSPACE%%}/g, workspace)
.replace(/{%%CURRENT_YEAR%%}/g, String(new Date().getFullYear()))
Expand Down
7 changes: 4 additions & 3 deletions packages/core/copy-uuid/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'copy-uuid'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
7 changes: 4 additions & 3 deletions packages/core/i18n/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'i18n'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
7 changes: 4 additions & 3 deletions packages/core/misc-widgets/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'misc-widgets'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
7 changes: 4 additions & 3 deletions packages/portal/document-viewer/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'document-viewer'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
7 changes: 4 additions & 3 deletions packages/portal/spec-renderer/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import sharedViteConfig from '../../../vite.config.shared'
import sharedViteConfig, { sanitizePackageName } from '../../../vite.config.shared'
import vue from '@vitejs/plugin-vue'
import ViteYaml from '@modyfi/vite-plugin-yaml'
import { resolve } from 'path'
import { defineConfig, mergeConfig } from 'vite'

// Package name MUST always match the kebab-case package name inside the component's package.json file and the name of your `/packages/{package-name}` directory
const packageName = 'spec-renderer'
const sanitizedPackageName = sanitizePackageName(packageName)

// Merge the shared Vite config with the local one defined below
const config = mergeConfig(sharedViteConfig, defineConfig({
build: {
lib: {
// The kebab-case name of the exposed global variable. MUST be in the format `kong-ui-public-{package-name}`
// Example: name: 'kong-ui-public-demo-component'
name: `kong-ui-public-${packageName}`,
name: `kong-ui-public-${sanitizedPackageName}`,
entry: resolve(__dirname, './src/index.ts'),
fileName: (format) => `${packageName}.${format}.js`,
fileName: (format) => `${sanitizedPackageName}.${format}.js`,
},
},
}))
Expand Down
Loading