@ordergroove/smi-serve 1.6.2 → 1.7.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.7.1](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.7.0...@ordergroove/smi-serve@1.7.1) (2024-04-19)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * get hot reloading working for less ([51fd2aa](https://github.com/ordergroove/plush-toys/commit/51fd2aad37234c0f931aafc4a268b9ad996f4a7b))
12
+ * prevent FOUC when hot-reloading stylesheet ([6f6c416](https://github.com/ordergroove/plush-toys/commit/6f6c416c5b3f66f78eb0e7d0c5d2c39c2368ce7c))
13
+
14
+
15
+
16
+
17
+
18
+ # [1.7.0](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.6.2...@ordergroove/smi-serve@1.7.0) (2024-04-19)
19
+
20
+
21
+ ### Features
22
+
23
+ * use smi-preview data in smi-serve ([4ed09e7](https://github.com/ordergroove/plush-toys/commit/4ed09e7494cde0352151e77d168e412c9c9a538b))
24
+
25
+
26
+
27
+
28
+
6
29
  ## [1.6.2](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.6.1...@ordergroove/smi-serve@1.6.2) (2024-04-18)
7
30
 
8
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/smi-serve",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "description": "Utility to serve a SMI template locally",
5
5
  "keywords": [],
6
6
  "author": "Eugenio Lattanzio <eugenio.lattanzio@ordergroove.com>",
@@ -32,5 +32,5 @@
32
32
  "ora": "^5.4.1",
33
33
  "yargs": "^17.7.2"
34
34
  },
35
- "gitHead": "08e75f787367ce639b591f9e2f2402cfb8badfe6"
35
+ "gitHead": "6b6773a874a08a98783bae542c047dec8cfb69bf"
36
36
  }
@@ -1,24 +1,19 @@
1
- /* eslint "no-undef": "off" */
2
- /* eslint "no-nested-ternary": "off" */
3
- const params = new URLSearchParams(document.location.hash.substring(1) || window.location.search);
1
+ // virtual JSON file containing build-time variables
2
+ import { OG_ENV, OG_MERCHANT_ID, OG_HMAC_AUTH, OG_SMI_CORE_VERSION } from 'virtual:globals.json';
4
3
 
5
- const auth_merchant_id = params.get('m') || params.get('merchant_id') || (params.get('auth') || '').split('|')[3];
6
- const auth_env = params.get('env') || (params.has('prod') && 'prod') || (params.has('staging') && 'staging') || OG_ENV;
7
- const template_merchant_id = (params.get('t') || '').split(',')[0];
8
- const is_staging = auth_env.startsWith('s');
4
+ const params = new URLSearchParams(window.location.search);
9
5
 
10
- export const merchant_id = params.has('auth')
11
- ? template_merchant_id || auth_merchant_id || OG_MERCHANT_ID || '0e5de2bedc5e11e3a2e4bc764e106cf4'
12
- : OG_MERCHANT_ID || '0e5de2bedc5e11e3a2e4bc764e106cf4';
6
+ const env = params.get('env') || OG_ENV;
7
+
8
+ export const merchant_id = params.get('merchant_id') || OG_MERCHANT_ID;
13
9
 
14
10
  export const auth_config = params.has('auth')
15
11
  ? {
16
- env: is_staging ? 'staging' : 'prod',
17
- auth: params.has('auth')
12
+ env,
13
+ auth: params.get('auth')
18
14
  }
19
15
  : OG_HMAC_AUTH
20
16
  ? { env: OG_ENV, auth: OG_HMAC_AUTH }
21
- : {
22
- auth_url: 'https://static-origin-server.ordergroove.com/0e5de2bedc5e11e3a2e4bc764e106cf4/demo/auth.json',
23
- env: 'staging'
24
- };
17
+ : null;
18
+
19
+ export const smi_core_version = OG_SMI_CORE_VERSION;
@@ -1,10 +1,36 @@
1
- import './styles/main.less';
2
- import mainTemplate from './views/main.liquid';
1
+ // ~/ refers to the working directory of the project using smi-serve
2
+ import mainTemplate from '~/views/main.liquid';
3
3
 
4
- import { merchant_id, auth_config } from './runtime-config';
4
+ import { merchant_id, auth_config, smi_core_version } from './devmode';
5
5
 
6
- const smi = window.og.smi;
6
+ // only run on initial load, not hot reload
7
+ if (!window.og?.smi) {
8
+ if (auth_config && merchant_id) {
9
+ waitForScriptToLoad(`https://static.ordergroove.com/@ordergroove/smi-core/${smi_core_version}/dist/smi.js`).then(
10
+ () => {
11
+ window.og.smi.bootstrap({ merchant_id, ...auth_config }, mainTemplate);
12
+ }
13
+ );
14
+ } else {
15
+ waitForScriptToLoad(`https://static.ordergroove.com/@ordergroove/smi-preview/latest/`).then(() => {
16
+ const smiPreview = window.og['smi-preview'];
17
+ const preview = smiPreview.createPreview(document.body, smi_core_version);
18
+ preview.template = mainTemplate;
19
+ preview.locale = 'en-US';
20
+ });
21
+ }
22
+ }
7
23
 
8
- smi.bootstrap({ merchant_id, ...auth_config }, mainTemplate);
24
+ async function waitForScriptToLoad(src) {
25
+ return new Promise((resolve, reject) => {
26
+ const script = document.createElement('script');
27
+ script.src = src;
28
+ script.addEventListener('load', () => {
29
+ resolve();
30
+ });
31
+ document.body.appendChild(script);
32
+ });
33
+ }
9
34
 
10
- export { mainTemplate, smi };
35
+ // export for the live reload script to use
36
+ export { mainTemplate };
@@ -3,24 +3,26 @@
3
3
  <title>SMI Demo Page</title>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <link rel="stylesheet" href="/entrypoint.css" />
7
- <script src="https://static.ordergroove.com/@ordergroove/smi-core/{{ SMI_CORE_VERSION }}/dist/smi.js"></script>
6
+ <link rel="stylesheet" href="/main.css" />
8
7
  <script>
9
8
  new EventSource('/esbuild').addEventListener('change', ev => {
10
- console.log('HRM', ev.data);
11
- let stylesheet = document.querySelector('link');
9
+ console.log('File changed, running hot reload');
10
+ let stylesheet = document.querySelector('link[rel="stylesheet"]');
12
11
  try {
13
12
  const { updated, added } = JSON.parse(ev.data);
14
13
  const ts = new Date().getTime();
15
- if (updated.includes('/entrypoint.css') || added.includes('/entrypoint.css')) {
16
- document.head.removeChild(stylesheet);
17
- stylesheet = document.createElement('link');
18
- stylesheet.rel = 'stylesheet';
19
- stylesheet.href = '/entrypoint.css?_=' + ts;
20
- document.head.appendChild(stylesheet);
14
+ if (updated.includes('/main.css') || added.includes('/main.css')) {
15
+ // https://esbuild.github.io/api/#hot-reloading-css
16
+ const newStylesheet = document.createElement('link');
17
+ newStylesheet.rel = 'stylesheet';
18
+ newStylesheet.href = '/main.css?_=' + ts;
19
+ // wait until new stylesheet has loading to prevent FOUC
20
+ newStylesheet.onload = () => stylesheet.remove();
21
+ document.head.appendChild(newStylesheet);
21
22
  }
22
23
  if (updated.includes('/entrypoint.js')) {
23
- import('./entrypoint.js?_=' + ts).then(({ mainTemplate, smi }) => {
24
+ import('./entrypoint.js?_=' + ts).then(({ mainTemplate }) => {
25
+ const smi = window.og.smi;
24
26
  smi.HTMLSmiElement.template = mainTemplate(smi.html);
25
27
  });
26
28
  }
package/src/serve.js CHANGED
@@ -8,7 +8,7 @@ const { getValidLoginAndCurrentMerchant } = require('./auth');
8
8
  const { open, getcwd, glob, readPackageJson, packageJsonKeys } = require('./utils');
9
9
  const { impersonate } = require('./impersonate');
10
10
 
11
- const setupSmiDevMode = async argv => {
11
+ async function getGlobals(argv) {
12
12
  let hmacAuth = "''",
13
13
  merchant,
14
14
  customer,
@@ -17,10 +17,23 @@ const setupSmiDevMode = async argv => {
17
17
  if ('impersonate' in argv) {
18
18
  [_token, merchant, customer] = await impersonate(argv);
19
19
 
20
- hmacAuth = customer && JSON.stringify([customer.merchant_user_id, customer.ts, customer.hash].join('|'));
20
+ hmacAuth = customer && [customer.merchant_user_id, customer.ts, customer.hash].join('|');
21
21
  }
22
22
 
23
+ const packageJson = readPackageJson();
24
+ const smiCoreVersion = packageJson[packageJsonKeys.OG_SECTION]?.[packageJsonKeys.CORE_VERSION] || 'latest';
25
+
23
26
  return {
27
+ OG_MERCHANT_ID: merchant ? merchant.public_id : '',
28
+ OG_HMAC_AUTH: hmacAuth,
29
+ OG_ENV: argv.env,
30
+ OG_SMI_CORE_VERSION: smiCoreVersion
31
+ };
32
+ }
33
+
34
+ const smiDevModePlugin = globals => {
35
+ /** @type {import('esbuild').Plugin} */
36
+ const plugin = {
24
37
  name: 'resolve_smi_templates',
25
38
  setup(build) {
26
39
  build.onLoad({ filter: /main\.liquid/ }, async () => {
@@ -45,49 +58,31 @@ const setupSmiDevMode = async argv => {
45
58
  };
46
59
  });
47
60
 
48
- build.onResolve({ filter: /(^entrypoint\.js$|^\.\/runtime-config(\.js)?$)/ }, args => {
49
- const c = {
61
+ // allow importing a non-existent 'virtual:globals.json' file containing build-time variables
62
+ const virtualGlobalsFilter = /^virtual:globals.json$/;
63
+ build.onResolve({ filter: virtualGlobalsFilter }, args => {
64
+ return {
50
65
  path: args.path,
51
- namespace: 'entrypoint-ns'
66
+ namespace: 'virtual-globals'
67
+ };
68
+ });
69
+ build.onLoad({ filter: virtualGlobalsFilter }, () => {
70
+ return {
71
+ contents: JSON.stringify(globals),
72
+ loader: 'json'
52
73
  };
53
- return c;
54
74
  });
55
75
 
56
- // Load paths tagged with the "env-ns" namespace and behave as if
57
- // they point to a JSON file containing the environment variables.
58
- build.onLoad({ filter: /(^entrypoint\.js$|^\.\/runtime-config(\.js)?$)/ }, async args => {
59
- // all this files have been resolved by precompile, here is only to list them in bundle
60
- if (args.path === 'entrypoint.js')
61
- return {
62
- contents: fs.existsSync(`${getcwd()}/${args.path}`)
63
- ? fs.readFileSync(`${getcwd()}/${args.path}`)
64
- : fs.readFileSync(`${__dirname}/partials/entrypoint.js`),
65
- resolveDir: getcwd(),
66
- loader: 'js',
67
- watchFiles: [path.resolve('./styles/main.less'), path.resolve('./views/main.liquid')]
68
- };
69
-
70
- if (args.path === './runtime-config') {
71
- const smiIndexSource = (
72
- await esbuild.transform(fs.readFileSync(`${__dirname}/partials/devmode.js`, 'utf8'), {
73
- define: {
74
- OG_MERCHANT_ID: merchant ? JSON.stringify(merchant.public_id) : "''",
75
- OG_HMAC_AUTH: hmacAuth,
76
- OG_ENV: JSON.stringify(argv.env)
77
- }
78
- })
79
- ).code;
80
-
81
- return {
82
- contents: smiIndexSource,
83
- loader: 'js',
84
- resolveDir: getcwd()
85
- };
86
- }
87
- throw new Error('Invalid loader');
76
+ // take imports starting with ~/ and resolve them inside the current working directory
77
+ build.onResolve({ filter: /^~\// }, args => {
78
+ return build.resolve(args.path.replace('~/', './'), {
79
+ kind: 'import-statement',
80
+ resolveDir: getcwd()
81
+ });
88
82
  });
89
83
  }
90
84
  };
85
+ return plugin;
91
86
  };
92
87
 
93
88
  async function serve(argv) {
@@ -103,19 +98,16 @@ async function serve(argv) {
103
98
 
104
99
  fs.mkdirSync(path.join(getcwd(), outdir), { recursive: true });
105
100
 
106
- const packageJson = readPackageJson();
107
- const smiCoreVersion = packageJson[packageJsonKeys.OG_SECTION]?.[packageJsonKeys.CORE_VERSION] || 'latest';
108
-
109
101
  const smiIndexFile = path.join(getcwd(), outdir, 'index.html');
110
- const smiIndexSource = fs
111
- .readFileSync(`${__dirname}/partials/index.html`, 'utf8')
112
- .replace('{{ SMI_CORE_VERSION }}', smiCoreVersion);
102
+ const smiIndexSource = fs.readFileSync(`${__dirname}/partials/index.html`, 'utf8');
113
103
  fs.writeFileSync(smiIndexFile, smiIndexSource, { encoding: 'utf8' });
114
104
 
105
+ const globals = await getGlobals(argv);
106
+
107
+ /** @type {import('esbuild').BuildOptions} */
115
108
  const buildConf = {
116
- entryPoints: {
117
- entrypoint: 'entrypoint.js'
118
- },
109
+ entryPoints: [path.join(__dirname, 'partials', 'entrypoint.js'), mainLess],
110
+ entryNames: '[name]',
119
111
 
120
112
  logLevel: verbose ? 'verbose' : 'error',
121
113
  nodePaths: [path.join(getcwd(), 'node_modules')],
@@ -129,7 +121,7 @@ async function serve(argv) {
129
121
  sourcemap: true,
130
122
 
131
123
  outdir: path.join(getcwd(), outdir),
132
- plugins: [await setupSmiDevMode(argv), lessLoader()]
124
+ plugins: [smiDevModePlugin(globals), lessLoader()]
133
125
  };
134
126
 
135
127
  if (!mainLess) {