From 9966c03e737841e835a2cb68157ad55dde53137e Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Wed, 2 Feb 2022 11:43:22 -0600 Subject: [PATCH] feat: services submodule, remove React components (#62) --- .gitignore | 1 + package.json | 7 ++ scripts/build-api.ts | 2 +- scripts/build-services.ts | 29 +++++++ scripts/build-utils.ts | 2 +- scripts/index.ts | 8 ++ scripts/utils.ts | 3 + src/integration/api-extractor.json | 2 +- src/{ => integration}/api.md | 23 ------ src/integration/forward.ts | 16 ---- src/integration/index.ts | 5 -- src/integration/services/facebook-pixel.ts | 21 ----- .../services/google-tag-manager.ts | 24 ------ src/react/api.md | 27 +------ src/react/forward.tsx | 17 ---- src/react/index.ts | 14 +--- src/react/integration/facebook-pixel.tsx | 63 --------------- src/react/integration/google-tag-manager.tsx | 78 ------------------- src/react/library.tsx | 23 ------ src/react/script.tsx | 52 ------------- src/react/snippet.tsx | 42 ++++++++++ src/services/api-extractor.json | 41 ++++++++++ src/services/api.md | 20 +++++ src/services/facebook-pixel.ts | 10 +++ src/{integration => }/services/freshpaint.ts | 4 +- src/services/google-tag-manager.ts | 8 ++ src/services/index.ts | 3 + src/services/package.json | 6 ++ tests/unit/integration.spec.ts | 16 ---- tsconfig.json | 1 + 30 files changed, 186 insertions(+), 382 deletions(-) create mode 100644 scripts/build-services.ts rename src/{ => integration}/api.md (72%) delete mode 100644 src/integration/forward.ts delete mode 100644 src/integration/services/facebook-pixel.ts delete mode 100644 src/integration/services/google-tag-manager.ts delete mode 100644 src/react/forward.tsx delete mode 100644 src/react/integration/facebook-pixel.tsx delete mode 100644 src/react/integration/google-tag-manager.tsx delete mode 100644 src/react/library.tsx delete mode 100644 src/react/script.tsx create mode 100644 src/react/snippet.tsx create mode 100644 src/services/api-extractor.json create mode 100644 src/services/api.md create mode 100644 src/services/facebook-pixel.ts rename src/{integration => }/services/freshpaint.ts (61%) create mode 100644 src/services/google-tag-manager.ts create mode 100644 src/services/index.ts create mode 100644 src/services/package.json diff --git a/.gitignore b/.gitignore index 1b231b00..6b24bc61 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ node_modules/ /tests/nextjs/public/ /tests/benchmarks/screenshots/ /tests/videos/ +/services/ /tsc/ /utils/ /index.cjs diff --git a/package.json b/package.json index 7c693027..a092d1db 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,12 @@ }, "./react/index.mjs": "./react/index.mjs", "./react/index.cjs": "./react/index.cjs", + "./services/index.mjs": "./services/index.mjs", + "./services/index.cjs": "./services/index.cjs", + "./services": { + "import": "./services/index.mjs", + "require": "./services/index.cjs" + }, "./utils": { "import": "./utils/index.mjs", "require": "./utils/index.cjs" @@ -41,6 +47,7 @@ "integration/", "lib/", "react/", + "services/", "utils/" ], "scripts": { diff --git a/scripts/build-api.ts b/scripts/build-api.ts index 36166709..eed07ebe 100644 --- a/scripts/build-api.ts +++ b/scripts/build-api.ts @@ -5,7 +5,7 @@ import { Extractor, ExtractorConfig } from '@microsoft/api-extractor'; export function buildApi(opts: BuildOptions) { console.log('👑 Generate API types\n'); - const dirs = [opts.srcIntegrationDir, opts.srcReactDir, opts.srcUtilsDir]; + const dirs = [opts.srcIntegrationDir, opts.srcServicesDir, opts.srcReactDir, opts.srcUtilsDir]; dirs.forEach((dir) => { const extractorConfig = ExtractorConfig.loadFileAndPrepare(join(dir, 'api-extractor.json')); const result = Extractor.invoke(extractorConfig, { diff --git a/scripts/build-services.ts b/scripts/build-services.ts new file mode 100644 index 00000000..e657d776 --- /dev/null +++ b/scripts/build-services.ts @@ -0,0 +1,29 @@ +import { BuildOptions, submodulePackageJson } from './utils'; +import { join } from 'path'; +import type { OutputOptions, RollupOptions } from 'rollup'; + +export function buildServices(opts: BuildOptions): RollupOptions { + const output: OutputOptions[] = [ + { + file: join(opts.distServicesDir, 'index.cjs'), + format: 'cjs', + }, + { + file: join(opts.distServicesDir, 'index.mjs'), + format: 'es', + }, + ]; + + return { + input: join(opts.tscServicesDir, 'index.js'), + output, + plugins: [ + submodulePackageJson( + '@builder.io/partytown/services', + opts.srcServicesDir, + opts.distServicesDir, + opts + ), + ], + }; +} diff --git a/scripts/build-utils.ts b/scripts/build-utils.ts index f62d7e1c..d7ad3d69 100644 --- a/scripts/build-utils.ts +++ b/scripts/build-utils.ts @@ -1,4 +1,4 @@ -import { BuildOptions, submodulePackageJson, submodulePath } from './utils'; +import { BuildOptions, submodulePackageJson } from './utils'; import { join } from 'path'; import type { RollupOptions } from 'rollup'; diff --git a/scripts/index.ts b/scripts/index.ts index 023f0347..fa192fd9 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -6,6 +6,7 @@ import { buildMediaImplementation } from './build-media-implementations'; import { buildMainSnippet } from './build-main-snippet'; import { buildReact } from './build-react'; import { buildServiceWorker } from './build-service-worker'; +import { buildServices } from './build-services'; import { buildUtils } from './build-utils'; import { emptyDir, ensureDir, readJsonSync, writeFile } from 'fs-extra'; import { join } from 'path'; @@ -25,6 +26,7 @@ export async function runBuild(rootDir: string, isDev: boolean, generateApi: boo ...buildAtomics(opts), buildMediaImplementation(opts), buildIntegration(opts), + buildServices(opts), buildReact(opts), buildUtils(opts), ]; @@ -63,6 +65,7 @@ async function createRootPackage(opts: BuildOptions) { function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolean) { const distIntegrationDir = join(rootDir, 'integration'); + const distServicesDir = join(rootDir, 'services'); const distLibDir = join(rootDir, 'lib'); const distLibDebugDir = join(distLibDir, 'debug'); const distReactDir = join(rootDir, 'react'); @@ -70,6 +73,7 @@ function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolea const srcDir = join(rootDir, 'src'); const srcIntegrationDir = join(srcDir, 'integration'); + const srcServicesDir = join(srcDir, 'services'); const srcLibDir = join(srcDir, 'lib'); const srcReactDir = join(srcDir, 'react'); const srcUtilsDir = join(srcDir, 'utils'); @@ -82,6 +86,7 @@ function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolea const tscDir = join(rootDir, 'tsc'); const tscSrcDir = join(tscDir, 'src'); const tscIntegrationDir = join(tscSrcDir, 'integration'); + const tscServicesDir = join(tscSrcDir, 'services'); const tscLibDir = join(tscSrcDir, 'lib'); const tscReactDir = join(tscSrcDir, 'react'); const tscUtilsDir = join(tscSrcDir, 'utils'); @@ -96,6 +101,7 @@ function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolea rootDir, distIntegrationDir, + distServicesDir, distLibDir, distLibDebugDir, distTestsLibDir, @@ -105,6 +111,7 @@ function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolea srcDir, srcIntegrationDir, + srcServicesDir, srcLibDir, srcReactDir, srcUtilsDir, @@ -114,6 +121,7 @@ function createBuildOptions(rootDir: string, isDev: boolean, generateApi: boolea tscDir, tscIntegrationDir, + tscServicesDir, tscLibDir, tscReactDir, tscUtilsDir, diff --git a/scripts/utils.ts b/scripts/utils.ts index de41de6b..76749b98 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -160,12 +160,14 @@ export interface BuildOptions { distIntegrationDir: string; distLibDir: string; distLibDebugDir: string; + distServicesDir: string; distTestsLibDir: string; distTestsLibDebugDir: string; distReactDir: string; distUtilsDir: string; srcDir: string; srcIntegrationDir: string; + srcServicesDir: string; srcLibDir: string; srcReactDir: string; srcUtilsDir: string; @@ -173,6 +175,7 @@ export interface BuildOptions { testsVideosDir: string; tscDir: string; tscIntegrationDir: string; + tscServicesDir: string; tscLibDir: string; tscReactDir: string; tscUtilsDir: string; diff --git a/src/integration/api-extractor.json b/src/integration/api-extractor.json index eab712cf..c4e67938 100644 --- a/src/integration/api-extractor.json +++ b/src/integration/api-extractor.json @@ -8,7 +8,7 @@ "apiReport": { "enabled": true, "reportFileName": "api.md", - "reportFolder": "/src/", + "reportFolder": "/src/integration/", "reportTempFolder": "/.cache/api-extractor/integration/" }, "dtsRollup": { diff --git a/src/api.md b/src/integration/api.md similarity index 72% rename from src/api.md rename to src/integration/api.md index e98c2776..d94e19a6 100644 --- a/src/api.md +++ b/src/integration/api.md @@ -4,39 +4,16 @@ ```ts -// @public -export const appendForwardConfig: (...forwards: PartytownForwardProperty[]) => string; - // Warning: (ae-forgotten-export) The symbol "ApplyHookOptions" needs to be exported by the entry point index.d.ts // // @public (undocumented) export type ApplyHook = (opts: ApplyHookOptions) => any; -// @public -export const facebookPixel: (opts: { - pixelId: string; -}) => string; - -// @public -export const facebookPixelForward: () => PartytownForwardProperty[]; - -// @public -export const freshpaintForward: () => PartytownForwardProperty[]; - // Warning: (ae-forgotten-export) The symbol "GetHookOptions" needs to be exported by the entry point index.d.ts // // @public (undocumented) export type GetHook = (opts: GetHookOptions) => any; -// @public -export const googleTagManager: (opts: { - containerId: string; - dataLayerName?: string; -}) => string; - -// @public -export const googleTagManagerForward: () => PartytownForwardProperty[]; - // @public export interface PartytownConfig { // (undocumented) diff --git a/src/integration/forward.ts b/src/integration/forward.ts deleted file mode 100644 index e99d0e3b..00000000 --- a/src/integration/forward.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { PartytownForwardProperty } from '../lib/types'; - -/** - * Gracefully adds a forward property to the global Partytown config. This - * first ensures the `window.partytown.foward` exists, then adds the forward - * property. - * - * @public - */ -export const appendForwardConfig = (...forwards: PartytownForwardProperty[]) => { - if (forwards.length > 0) { - const str = forwards.map((f) => JSON.stringify(f)).join(','); - return `!(function(w,p,f,c){c=w[p]=w[p]||{};(c[f]=c[f]||[]).push(${str})})(window,'partytown','forward');`; - } - return ``; -}; diff --git a/src/integration/index.ts b/src/integration/index.ts index 15c375e3..eeee8858 100644 --- a/src/integration/index.ts +++ b/src/integration/index.ts @@ -11,13 +11,8 @@ import type { PartytownConfig } from '../lib/types'; export const partytownSnippet = (config: PartytownConfig) => createSnippet(config, PartytownSnippet); -export { appendForwardConfig } from './forward'; export { SCRIPT_TYPE } from '../lib/utils'; -export * from './services/facebook-pixel'; -export * from './services/freshpaint'; -export * from './services/google-tag-manager'; - export type { PartytownConfig, PartytownForwardProperty, diff --git a/src/integration/services/facebook-pixel.ts b/src/integration/services/facebook-pixel.ts deleted file mode 100644 index e2cadba2..00000000 --- a/src/integration/services/facebook-pixel.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { PartytownForwardProperty } from '../../lib/types'; - -/** - * Facebook Pixel script. - * - * https://developers.facebook.com/docs/facebook-pixel/get-started - * - * @public - */ -export const facebookPixel = (opts: { pixelId: string }) => - `!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, document,'script','https://connect.facebook.net/en_US/fbevents.js'); -fbq('init',${JSON.stringify(opts.pixelId)});fbq('track','PageView');`; - -/** - * Forwards Facebool Pixels main window calls to Partytown's worker thread. - * - * https://developers.facebook.com/docs/facebook-pixel/get-started - * - * @public - */ -export const facebookPixelForward = (): PartytownForwardProperty[] => ['fbq']; diff --git a/src/integration/services/google-tag-manager.ts b/src/integration/services/google-tag-manager.ts deleted file mode 100644 index bbd91d08..00000000 --- a/src/integration/services/google-tag-manager.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { PartytownForwardProperty } from '../../lib/types'; - -/** - * Google Tag Manager script. - * - * https://developers.google.com/tag-manager/quickstart - * - * @public - */ -export const googleTagManager = (opts: { containerId: string; dataLayerName?: string }) => - `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': - new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], - j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= - 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); - })(window,document,'script',${JSON.stringify(opts.dataLayerName || 'dataLayer')},${JSON.stringify( - opts.containerId - )});`; - -/** - * Forwards Google Tag Manager main window calls to Partytown's worker thread. - * - * @public - */ -export const googleTagManagerForward = (): PartytownForwardProperty[] => ['dataLayer.push']; diff --git a/src/react/api.md b/src/react/api.md index b27eb46c..f7ded2b8 100644 --- a/src/react/api.md +++ b/src/react/api.md @@ -5,32 +5,7 @@ ```ts // @public -export const FacebookPixel: ({ pixelId, enablePartytown }: FacebookPixelProps) => any; - -// @public (undocumented) -export const FacebookPixelNoScript: ({ pixelId }: FacebookPixelProps) => any; - -// @public -export interface FacebookPixelProps { - enablePartytown?: boolean; - pixelId: string; -} - -// @public -export const GoogleTagManager: ({ containerId, dataLayerName, enablePartytown, }: GoogleTagManagerProps) => any; - -// @public -export const GoogleTagManagerNoScript: ({ containerId }: GoogleTagManagerProps) => any; - -// @public -export interface GoogleTagManagerProps { - containerId: string; - dataLayerName?: string; - enablePartytown?: boolean; -} - -// @public -export const Partytown: (props?: PartytownProps | undefined) => any; +export const Partytown: (props?: PartytownProps) => any; // Warning: (ae-forgotten-export) The symbol "PartytownConfig" needs to be exported by the entry point index.d.ts // diff --git a/src/react/forward.tsx b/src/react/forward.tsx deleted file mode 100644 index 51502b1a..00000000 --- a/src/react/forward.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { appendForwardConfig } from '@builder.io/partytown/integration'; -import { PartytownScript } from './script'; -import type { PartytownForwardProperty } from '../lib/types'; - -export interface PartytownForwardProps { - id: string; - forward: PartytownForwardProperty[]; -} - -export const PartytownForward = ({ id, forward }: PartytownForwardProps) => { - const forwardScript = appendForwardConfig(...forward); - if (forwardScript) { - return ; - } - return null; -}; diff --git a/src/react/index.ts b/src/react/index.ts index 18432561..f9943974 100644 --- a/src/react/index.ts +++ b/src/react/index.ts @@ -1,13 +1 @@ -export { Partytown, PartytownProps } from './library'; - -export { - FacebookPixel, - FacebookPixelNoScript, - FacebookPixelProps, -} from './integration/facebook-pixel'; - -export { - GoogleTagManager, - GoogleTagManagerNoScript, - GoogleTagManagerProps, -} from './integration/google-tag-manager'; +export { Partytown, PartytownProps } from './snippet'; diff --git a/src/react/integration/facebook-pixel.tsx b/src/react/integration/facebook-pixel.tsx deleted file mode 100644 index f9437b80..00000000 --- a/src/react/integration/facebook-pixel.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, { Fragment } from 'react'; -import { - facebookPixel, - facebookPixelForward, - SCRIPT_TYPE, -} from '@builder.io/partytown/integration'; -import { PartytownScript } from '../script'; -import { PartytownForward } from '../forward'; - -/** - * https://www.facebook.com/business/help/952192354843755?id=1205376682832142 - * - * @public - */ -export interface FacebookPixelProps { - /** - * Facebook Pixel Id - */ - pixelId: string; - - /** - * Setting to `false` will disable using Partytown and instead execute this script the traditional way. - */ - enablePartytown?: boolean; -} - -/** - * The Facebook Pixel Partytown component should be added after the opening `` - * tag, but before the `` component. - * - * https://www.facebook.com/business/help/952192354843755?id=1205376682832142 - * - * @public - */ -export const FacebookPixel = ({ pixelId, enablePartytown }: FacebookPixelProps): any => { - const usePartytown = enablePartytown !== false; - return ( - - {usePartytown ? : null} - - - ); -}; - -/** - * @public - */ -export const FacebookPixelNoScript = ({ pixelId }: FacebookPixelProps): any => ( - -); diff --git a/src/react/integration/google-tag-manager.tsx b/src/react/integration/google-tag-manager.tsx deleted file mode 100644 index 62239e6b..00000000 --- a/src/react/integration/google-tag-manager.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { Fragment } from 'react'; -import { - googleTagManager, - googleTagManagerForward, - SCRIPT_TYPE, -} from '@builder.io/partytown/integration'; -import { PartytownScript } from '../script'; -import { PartytownForward } from '../forward'; - -/** - * https://developers.google.com/tag-manager/quickstart - * - * @public - */ -export interface GoogleTagManagerProps { - /** - * Google Tag Manager Container ID, formatted as GTM-XXXXXX - */ - containerId: string; - - /** - * The default name of the data layer object initiated by the global site tag or Tag Manager is `dataLayer`. - * Use this prop to use a different name for your data layer. - */ - dataLayerName?: string; - - /** - * Setting to `false` will disable using Partytown and instead execute this script the traditional way. - */ - enablePartytown?: boolean; -} - -/** - * The Google Tag Manager Partytown component should be added after the opening `` - * tag, but before the `` component. This component will add the - * [Data Layer](https://developers.google.com/tag-manager/devguide) to the main thread - * window, and will load GTM within the web worker. Any updates to `dataLayer.push(...)` - * will be forwarded to the Partytown web worker. - * - * https://developers.google.com/tag-manager/quickstart - * - * @public - */ -export const GoogleTagManager = ({ - containerId, - dataLayerName, - enablePartytown, -}: GoogleTagManagerProps): any => { - const usePartytown = enablePartytown !== false; - return ( - - {usePartytown ? : null} - - - ); -}; - -/** - * The GTM No Script component should be added immediately after the opening `` tag. - * - * https://developers.google.com/tag-manager/quickstart - * - * @public - */ -export const GoogleTagManagerNoScript = ({ containerId }: GoogleTagManagerProps): any => ( - -); diff --git a/src/react/library.tsx b/src/react/library.tsx deleted file mode 100644 index 18946978..00000000 --- a/src/react/library.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import type { PartytownConfig } from '../lib/types'; -import { partytownSnippet } from '@builder.io/partytown/integration'; -import { PartytownScript } from './script'; - -/** - * Props for ``, which extends the Partytown Config. - * - * https://github.com/BuilderIO/partytown#config - * - * @public - */ -export interface PartytownProps extends PartytownConfig {} - -/** - * The React `` component should be placed within the `` - * of the document, and after any integrations such as ``. - * - * @public - */ -export const Partytown = (props?: PartytownProps): any => ( - -); diff --git a/src/react/script.tsx b/src/react/script.tsx deleted file mode 100644 index 57a4562e..00000000 --- a/src/react/script.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useEffect } from 'react'; -import { SCRIPT_TYPE } from '@builder.io/partytown/integration'; - -export interface PartytownScriptProps { - /** - * Must be a unique id, and sets the `data-pt-script` attribute - * which is used as a selector to ensure the same script isn't executed - * more than once. - */ - id: string; - innerHTML: string; - type?: string; -} - -/** - * React script component created for these scenarios: - * - SSR/Static rendered HTML, without Client JS running - * - Client JS only, without starting with rendered SSR/Static HTML - * - SSR/Static rendered HTML, that is then hydrated with Client JS - * - * This component ensures each scenario works, and that the script is only - * executed once (to include not re-executing during Hot Module Reloading). - * Also ensures it does nothing for scripts with [type="text/partytown"]. - */ -export const PartytownScript = ({ id, innerHTML, type }: PartytownScriptProps): any => { - useEffect(() => { - if (typeof document !== 'undefined' && type !== SCRIPT_TYPE) { - if (!document.querySelector(`script[data-pt-script="${id}"]`)) { - // Client side, that's not a Partytown script, that should run on main - // SSR/Static script does not exist, this must be client only - // append the script script that should have run and append to the head - const scriptElm = document.createElement('script'); - scriptElm.dataset.ptScript = id; - scriptElm.innerHTML = innerHTML; - if (type) { - scriptElm.setAttribute('type', type); - } - document.head.appendChild(scriptElm); - } - } - }, []); - - // `dangerouslySetInnerHTML` only works for scripts rendered as HTML from SSR/Static. - // Added code will set the [type="data-pt-script"] attribute with the unique id. - // If this code renders as SSR/Static HTML, then it'll execute and add the attribute - // which will tell the Client JS of the component to NOT add the same script to the head. - let jsxInnerHTML = innerHTML; - if (type !== SCRIPT_TYPE) { - jsxInnerHTML = `document.currentScript.dataset.ptScript=${JSON.stringify(id)};` + jsxInnerHTML; - } - return