@hubspot/ui-extensions-dev-server 0.0.1-prealpha.3 → 0.0.1-prealpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.js CHANGED
@@ -6,21 +6,23 @@ async function buildAllExtensions(config, outputDir) {
6
6
  for (let i = 0; i < extensionKeys.length; ++i) {
7
7
  const { data } = config[extensionKeys[i]];
8
8
 
9
- await buildSingleExtension(
10
- data?.module.file,
11
- data?.output,
9
+ await buildSingleExtension({
10
+ file: data?.module.file,
11
+ outputFileName: data?.output,
12
12
  outputDir,
13
- i === 0
14
- );
13
+ emptyOutDir: i === 0,
14
+ });
15
15
  }
16
16
  }
17
17
 
18
- async function buildSingleExtension(
18
+ async function buildSingleExtension({
19
19
  file,
20
20
  outputFileName,
21
21
  outputDir,
22
- emptyOutDir = true
23
- ) {
22
+ emptyOutDir = true,
23
+ plugins = { rollup: [], vite: [] },
24
+ minify = false,
25
+ }) {
24
26
  await build({
25
27
  build: {
26
28
  lib: {
@@ -29,10 +31,14 @@ async function buildSingleExtension(
29
31
  formats: ['iife'],
30
32
  fileName: () => outputFileName,
31
33
  },
32
- rollupOptions: ROLLUP_OPTIONS,
34
+ rollupOptions: {
35
+ ...ROLLUP_OPTIONS,
36
+ plugins: [...(ROLLUP_OPTIONS.plugins || []), ...plugins?.rollup],
37
+ },
33
38
  outDir: outputDir,
34
39
  emptyOutDir,
35
- minify: false,
40
+ minify,
41
+ plugins: plugins?.vite,
36
42
  },
37
43
  });
38
44
  }
package/cli.js CHANGED
@@ -43,12 +43,14 @@ function showHelp(OUTPUT_DIR) {
43
43
  optionList: [
44
44
  {
45
45
  name: 'extension',
46
+ alias: 'e',
46
47
  typeLabel: '{underline file}',
47
48
  description:
48
- 'The extension entrypoint file build or start local development for',
49
+ 'The extension entrypoint file to build or start local development for',
49
50
  },
50
51
  {
51
52
  name: 'help',
53
+ alias: 'h',
52
54
  description: 'Print this usage guide.',
53
55
  },
54
56
  ],
package/config.js CHANGED
@@ -71,30 +71,47 @@ function loadConfig() {
71
71
 
72
72
  const mainAppConfig = _loadRequiredConfigFile(configPath);
73
73
 
74
- if (!mainAppConfig?.extensions?.crm?.cards) {
74
+ const crmCardsSubConfigFiles = mainAppConfig?.extensions?.crm?.cards;
75
+ if (!crmCardsSubConfigFiles) {
75
76
  logger.error(
76
- `"extensions.crm.cards" is missing in ${configPath}, it is a required configuration property`
77
+ `The "extensions.crm.cards" array in ${configPath} is missing, it is a required configuration property`
78
+ );
79
+ process.exit(1);
80
+ } else if (crmCardsSubConfigFiles.length === 0) {
81
+ logger.error(
82
+ `The "extensions.crm.cards" array in ${configPath} is empty, it is a required configuration property.`
77
83
  );
78
84
  process.exit(1);
79
85
  }
80
86
 
81
87
  const outputConfig = {};
82
88
 
83
- mainAppConfig.extensions.crm.cards.forEach(card => {
89
+ crmCardsSubConfigFiles.forEach(card => {
84
90
  const extensionsRemoved = card.file.replace('extensions/', '');
85
- const cardPath = path.join(process.cwd(), extensionsRemoved);
91
+ const cardConfigPath = path.join(process.cwd(), extensionsRemoved);
92
+ // Get the path to the config file relative to the extensions directory
93
+ const configPathRelativeToExtensions = path.parse(extensionsRemoved)?.dir;
94
+
86
95
  try {
87
- const cardConfig = require(cardPath);
88
- const extensionFileName = cardConfig.data?.module?.file;
89
- outputConfig[extensionFileName] = cardConfig;
90
- outputConfig[extensionFileName].data.output = getUrlSafeFileName(
96
+ const cardConfig = require(cardConfigPath);
97
+
98
+ // Join the two relative paths
99
+ const entryPointPath = path.join(
100
+ configPathRelativeToExtensions,
91
101
  cardConfig.data?.module?.file
92
102
  );
93
- outputConfig[extensionFileName].data.appName = projectConfig.name;
103
+
104
+ cardConfig.data.module.file = entryPointPath;
105
+
106
+ outputConfig[entryPointPath] = cardConfig;
107
+ outputConfig[entryPointPath].data.output = getUrlSafeFileName(
108
+ entryPointPath
109
+ );
110
+ outputConfig[entryPointPath].data.appName = projectConfig.name;
94
111
  } catch (e) {
95
112
  let errorMessage = e?.message;
96
113
  if (e?.code === 'MODULE_NOT_FOUND') {
97
- errorMessage = `Unable to load "${cardPath}" file. \nPlease make sure you are running the command from the src/app/extensions directory and that your card JSON config exists within it.`;
114
+ errorMessage = `Unable to load "${cardConfigPath}" file. \nPlease make sure you are running the command from the src/app/extensions directory and that your card JSON config exists within it.`;
98
115
  }
99
116
 
100
117
  logger.error(errorMessage);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-dev-server",
3
- "version": "0.0.1-prealpha.3",
3
+ "version": "0.0.1-prealpha.4",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -45,5 +45,16 @@
45
45
  "node": true
46
46
  }
47
47
  },
48
- "gitHead": "74dbffa7fe6e4ad7d5029897801c11dc5d5edae1"
48
+ "engines": {
49
+ "node": ">=16"
50
+ },
51
+ "peerDependencies": {
52
+ "typescript": "^5.0.4"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "typescript": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "gitHead": "d3ed42de0f9675a2f599416ba1886ba379ecfcd0"
49
60
  }
package/remoteBuild.js CHANGED
@@ -2,20 +2,29 @@
2
2
  const { OUTPUT_DIR } = require('./constants');
3
3
  const { getUrlSafeFileName } = require('./utils');
4
4
  const { buildSingleExtension } = require('./build');
5
+ const path = require('path');
6
+ const manifestPlugin = require('./plugins/manifestPlugin');
5
7
 
6
- // Regular expressions to match files ending in ts, js, tsx, and jsx
7
- const entryPointRegex = new RegExp(/.*\.(ts|js)[x]?$/);
8
+ const entryPoint = process.argv[process.argv.length - 1];
8
9
 
9
- let extension = process.argv[process.argv.length - 1];
10
+ const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx'];
10
11
 
11
- if (!entryPointRegex.test(extension)) {
12
+ const fileInfo = path.parse(entryPoint);
13
+
14
+ if (!allowedExtensions.includes(fileInfo.ext)) {
12
15
  throw new Error(
13
- 'The last argument should be the filename you wish to build. Supported file extensions are [ts, tsx, js, jsx]'
16
+ `The last argument should be the filename you wish to build. Supported file extensions are [${allowedExtensions.join(
17
+ ', '
18
+ )}]`
14
19
  );
15
20
  }
16
21
 
17
- // The incoming filename may be the full path the the file, so split the string
18
- // to remove any directory prefix up until the extensions directory
19
- extension = extension.split('extensions/').pop();
20
-
21
- buildSingleExtension(extension, getUrlSafeFileName(extension), OUTPUT_DIR);
22
+ buildSingleExtension({
23
+ file: entryPoint,
24
+ outputFileName: getUrlSafeFileName(entryPoint),
25
+ outputDir: OUTPUT_DIR,
26
+ plugins: {
27
+ rollup: [manifestPlugin({ minify: true })],
28
+ },
29
+ minify: true,
30
+ });
package/run.js CHANGED
@@ -6,6 +6,7 @@ const { buildAllExtensions, buildSingleExtension } = require('./build');
6
6
  const { VITE_DEFAULT_PORT, OUTPUT_DIR } = require('./constants');
7
7
  const { parseArgs, showHelp } = require('./cli');
8
8
  const { getUrlSafeFileName } = require('./utils');
9
+ const manifestPlugin = require('./plugins/manifestPlugin');
9
10
 
10
11
  const { DEV_MODE, BUILD_MODE, port, extension, help } = parseArgs();
11
12
  const PORT = port || VITE_DEFAULT_PORT;
@@ -18,7 +19,12 @@ if (DEV_MODE) {
18
19
  startDevMode(loadConfig(), OUTPUT_DIR, PORT, extension);
19
20
  } else if (BUILD_MODE) {
20
21
  if (extension) {
21
- buildSingleExtension(extension, getUrlSafeFileName(extension), OUTPUT_DIR);
22
+ buildSingleExtension({
23
+ file: extension,
24
+ outputFileName: getUrlSafeFileName(extension),
25
+ outputDir: OUTPUT_DIR,
26
+ plugins: { rollup: [manifestPlugin()] },
27
+ });
22
28
  } else {
23
29
  buildAllExtensions(loadConfig(), OUTPUT_DIR);
24
30
  }
@@ -14,19 +14,37 @@ function _testHelper(command, outputDirFiles) {
14
14
  // Spot check the file contents to make sure they seem ok
15
15
  filesInOutputDir.forEach(file => {
16
16
  const fileContents = fs.readFileSync(path.join(distDir, file)).toString();
17
- const stringsToSpotCheck = [
18
- '.createRemoteReactComponent',
19
- '.createElement',
20
- 'hubspot.extend',
21
- 'React',
22
- 'RemoteUI',
23
- ];
24
- stringsToSpotCheck.forEach(stringToCheck => {
25
- assert(
26
- fileContents.includes(stringToCheck),
27
- `File ${file} contents should contain: "${stringToCheck}"`
28
- );
29
- });
17
+ if (file === 'manifest.json') {
18
+ const manifest = JSON.parse(fileContents);
19
+ assert(manifest.entry);
20
+ assert(manifest.modules);
21
+ assert(manifest.modules.internal);
22
+ manifest.modules.internal.forEach(mod => {
23
+ assert(mod.module);
24
+ assert(mod.renderedExports);
25
+ });
26
+ assert(manifest.modules.external);
27
+ manifest.modules.external.forEach(mod => {
28
+ assert(mod.module);
29
+ assert(mod.renderedExports);
30
+ });
31
+ assert(manifest.package);
32
+ assert(manifest.package.packages);
33
+ } else {
34
+ const stringsToSpotCheck = [
35
+ '.createRemoteReactComponent',
36
+ '.createElement',
37
+ 'hubspot.extend',
38
+ 'React',
39
+ 'RemoteUI',
40
+ ];
41
+ stringsToSpotCheck.forEach(stringToCheck => {
42
+ assert(
43
+ fileContents.includes(stringToCheck),
44
+ `File ${file} contents should contain: "${stringToCheck}"`
45
+ );
46
+ });
47
+ }
30
48
  });
31
49
  }
32
50
 
@@ -43,7 +61,7 @@ function testBuildWithExtensionFlag(logger) {
43
61
  logger.warn('- Test build with flags started 🤞');
44
62
  _testHelper(
45
63
  'hs-ui-extensions-dev-server build --extension ProgressBarApp.tsx',
46
- ['ProgressBarApp.js']
64
+ ['ProgressBarApp.js', 'manifest.json']
47
65
  );
48
66
  logger.info('- Test build with flags passed 🚀');
49
67
  }
@@ -52,19 +70,11 @@ function testDefInfraBuildFileName(logger) {
52
70
  logger.warn('- Test build with entrypoint as arg 🤞');
53
71
  _testHelper('hs-ui-extensions-remote-build ProgressBarApp.tsx', [
54
72
  'ProgressBarApp.js',
73
+ 'manifest.json',
55
74
  ]);
56
75
  logger.info('- Test build with entrypoint as arg 🚀');
57
76
  }
58
77
 
59
- function testDevInfraBuildFileNameWithPathPrefix(logger) {
60
- logger.warn('- Test build with config file as arg 🤞');
61
- _testHelper(
62
- 'hs-ui-extensions-remote-build some/super/long/file/path/to/the/extensions/PhoneLines.tsx',
63
- ['PhoneLines.js']
64
- );
65
- logger.info('- Test build with config file as arg 🚀');
66
- }
67
-
68
78
  function testBuild(logger) {
69
79
  logger.warn('\nBuild Tests started - External Devs 🤞');
70
80
  testDefaultBuildPath(logger);
@@ -73,7 +83,6 @@ function testBuild(logger) {
73
83
 
74
84
  logger.warn('\nBuild Tests started - Dev Infra 🤞');
75
85
  testDefInfraBuildFileName(logger);
76
- testDevInfraBuildFileNameWithPathPrefix(logger);
77
86
  logger.info('Build Tests passed - Dev Infra 🚀');
78
87
  }
79
88
 
package/utils.js CHANGED
@@ -1,7 +1,8 @@
1
+ const path = require('path');
2
+
1
3
  function getUrlSafeFileName(filePath) {
2
- const fileName = filePath.split('/').pop();
3
- const fileNameWithJsExtension = fileName.replace(/\.ts[x]?$|\.jsx$/g, '.js');
4
- return encodeURIComponent(fileNameWithJsExtension);
4
+ const { name } = path.parse(filePath);
5
+ return encodeURIComponent(`${name}.js`);
5
6
  }
6
7
 
7
8
  module.exports = {