@syncify/cli 0.1.0-beta

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/readme.md ADDED
@@ -0,0 +1,1840 @@
1
+ **BETA VERSION**
2
+
3
+ <hr>
4
+
5
+ # @liquify/syncify
6
+
7
+ A lightening fast, extensible and superior alternative Shopify CLI ([theme kit](https://shopify.github.io/themekit/)) tool. Syncify is a powerful and informative CLI which employs an intuitive approach for Shopify theme development.
8
+
9
+ **Syncify exists as part of the [Liquify](https://liquify.dev) project**
10
+
11
+ ### Key Features
12
+
13
+ - Watch, upload, download and export multiple storefronts and themes.
14
+ - Intelligent path mapping capabilities for custom directory structures.
15
+ - HOT reloading of assets, section, snippets, templates and layouts.
16
+ - Clear, concise, informative and beautiful CLI logging.
17
+ - An elegant global directory based metafields sync approach using JSON files.
18
+ - Digests and spawns existing build tools for asset transformations.
19
+ - Exposed Plugin API for adding those seeking extensibility.
20
+ - Prompt based CLI/TUI and exposed module API for script usage.
21
+ - Pull, push and merge support for aligning local and remote sources.
22
+ - Files, Pages and Redirects sync strategies and support.
23
+
24
+ ### Why?
25
+
26
+ I have been working on the Shopify platform for last several years and nothing the Shopify team maintain or have produced has actually helped me and their tooling tends to impede upon my productivity. Alternatives like the Shopify CLI fail to achieve fluidity, either doing too much or not enough. Syncify is how I believe theme creation, development and maintenance should be handled. It's fast, flexible, extensible, scalable and will not lock you into some restrictive workflow and setup apparatus. It allows you to progressively enhance your development process and produce the most efficient and performant results.
27
+
28
+ # Install
29
+
30
+ Install as development dependency in your project.
31
+
32
+ **PNPM**
33
+
34
+ ```cli
35
+ pnpm add @syncify/syncify -D
36
+ ```
37
+
38
+ **NPM**
39
+
40
+ ```cli
41
+ npm i @syncify/syncify --save-dev
42
+ ```
43
+
44
+ **Yarn**
45
+
46
+ ```cli
47
+ yarn add @syncify/syncify --dev
48
+ ```
49
+
50
+ # Overview
51
+
52
+ The main purpose of Syncify is to facilitate seamless theme development between your local machine and Shopify store/s. It ships with build, watch, download, upload, merge and pull capabilities for interfacing with remote Shopify webshop's. Together with a prompt based execution model, Syncify provides developers with theme control that aims to exceed expectations.
53
+
54
+ ### Theme Files
55
+
56
+ Syncify uses built-in capabilities when handling snippets, templates, layouts, locales, configs and sections. Files using a `.liquid` or `.json` extension are typically considered theme files in syncify and always determined before handling. Content transformations like minification and path mappings are applied to these files types either natively or with plugins.
57
+
58
+ ### Data Files
59
+
60
+ Syncify exposes and introduces an elegant low-level method for interfacing with shop metafields, pages, redirects and files. Pull, push, merge and delete resource capabilities are provided for data identified files and for metafield resources a directory/file path based approach is employed which allows developers to advance their workflows in a controlled and extensible manner.
61
+
62
+ ### Asset Files
63
+
64
+ Syncify does not want to re-create or impede on developer preferences and tool appropriation. Build tools and bundlers specifically designed for processing different asset types can be spawned and run in parallel with Syncify's `build` and `watch` instances, but for more advanced use cases, Syncify also provides developers with pre-processor capabilities via plugins. Plugins can be leveraged for transforming TypeScript, JavaScript, CSS, SCSS and SVG file types and use wrappers around popular and performant modules.
65
+
66
+ ### Plugins
67
+
68
+ Syncify can be extended with Plugins. Similar to build tools like webpack and rollup, Syncify exposes a plugin API which allows you to hook into the build cycle and apply transforms to assets and files.
69
+
70
+ # Setup
71
+
72
+ After installing you will need to configure a connection to your shopify store. Syncify requires you provide either an admin API access token (recommended) or API Key and secret as credentials.
73
+
74
+ <details>
75
+ <summary>
76
+ <strong>Authorize</strong>
77
+ </summary>
78
+ <p>
79
+
80
+ You will need to create a [private app](https://help.shopify.com/en/manual/apps/private-apps) to obtain this information from Shopify. If you are coming from [Theme Kit](https://shopify.dev/themes/tools/theme-kit) you might be able to port those settings but it is recommended that you generate API access information specifically for usage with Syncify.
81
+
82
+ > There are plans to provide an official Syncify Shopify App to make this easier in future releases.
83
+
84
+ **Steps:**
85
+
86
+ 1. From your Shopify admin, go to **Apps**.
87
+ 2. Click **Develop apps**.
88
+ 3. Click **Create an app**.
89
+ 4. Provide an App name (eg: `Syncify`) and click **Create app**
90
+ 5. The app will be created, then click **Configure Admin API Scope**
91
+ 6. Select the required scopes (listed below)
92
+ 7. Click **Save**
93
+ 8. Goto the **API credentials** tab,
94
+ 9. Under **Access Tokens** press the **Install app** button.
95
+ 10. Press **Reveal token once** and copy the token into an `.env` file.
96
+
97
+ </p>
98
+ </details>
99
+
100
+ <details>
101
+ <summary>
102
+ <strong>Scopes</strong>
103
+ </summary>
104
+ <p>
105
+
106
+ You need to provide Syncify read and write access to a couple of admin endpoints so it can perform operations. Below are the required scopes you will need to enable within in your private app.
107
+
108
+ #### Files
109
+
110
+ - write_files
111
+ - read_files
112
+
113
+ #### Pages
114
+
115
+ - write_online_store_pages
116
+ - read_online_store_pages
117
+
118
+ #### Themes
119
+
120
+ - write_themes
121
+ - read_themes
122
+
123
+ </p>
124
+ </details>
125
+
126
+ # Credentials
127
+
128
+ Shop credentials can be stored within a `.env` or `.env.syncify.json` file. You can also provide credentials at runtime using `process.env` variables. The preferred approach is to store this information within a `.env` file.
129
+
130
+ ### Using a `.env` file
131
+
132
+ When using a `.env` file, you can provide shop credentials in either uppercase of lowercase format. The `.env` values **must** begin with the shop name following an underscore `_` character. If you are syncing to multiple storefronts just follow the pattern for each store.
133
+
134
+ Using an **API Access Token**
135
+
136
+ ```env
137
+ YOUR-SHOP-NAME_API_TOKEN = 'shpat_abcdefghijklmnopqrstuvwz'
138
+ ```
139
+
140
+ Using an **API key** and **API Secret**
141
+
142
+ ```env
143
+ YOUR-SHOP-NAME_API_KEY = 'abcdefghijklmnopqrstuvwz'
144
+ YOUR-SHOP-NAME_API_SECRET = 'abcdefghijklmnopqrstuvwz'
145
+ ```
146
+
147
+ ### Using `process.env` variables
148
+
149
+ Syncify also supports runtime credential assignment. This approach allows you to set credentials via the command line or within a script executable. This is highly discouraged and rather insecure.
150
+
151
+ Using an **API Access Token**
152
+
153
+ ```js
154
+ // Using an API Access Token
155
+ process.env['YOUR-SHOP-NAME_API_TOKEN'] = 'shpat_abcdefghijklmnopqrstuvwz';
156
+ ```
157
+
158
+ Using an **API key** and **API Secret**
159
+
160
+ ```js
161
+ // Using an API Key and API Secret
162
+ process.env['YOUR-SHOP-NAME_API_KEY'] = 'abcdefghijklmnopqrstuvwz';
163
+ process.env['YOUR-SHOP-NAME_API_SECRET'] = 'abcdefghijklmnopqrstuvwz';
164
+ ```
165
+
166
+ # Package Schema
167
+
168
+ Syncify exposes a large set of configuration options. If you are using a text editor like [VS Code](https://code.visualstudio.com/) or one which supports [JSON Schema Specs](https://json-schema.org/specification.html) then you can extend `package.json` schemas. JSON schema specs provide features like hover descriptions, validations, auto-completion and intellisense for JSON file types. Extending the package schema will enable these capabilities be provided to the `syncify` field.
169
+
170
+ > It is **highly recommended** that you extend the `package.json` json specifications.
171
+
172
+ ### Generate Schemas (vscode users)
173
+
174
+ Syncify can automatically generate the `package.json` schema specs for developers using the VSCode text editor. The settings reference will be written within the `.vscode` directory relative to root. Use the following command:
175
+
176
+ ```
177
+ syncify --vsc
178
+ ```
179
+
180
+ ### Provide Manually
181
+
182
+ If you wish to provide the specs manually you will need to create a `.vscode` directory and `settings.json` file within. The `settings.json` should contain the following configuration settings:
183
+
184
+ ```json
185
+ {
186
+ "files.associations": {
187
+ ".syncifyrc": "json"
188
+ },
189
+ "json.schemas": [
190
+ {
191
+ "fileMatch": ["package.json"],
192
+ "url": "https://unpkg.com/@syncify/schema/package.json"
193
+ },
194
+ {
195
+ "fileMatch": [".syncifyrc", ".syncifyrc.json"],
196
+ "url": "https://unpkg.com/@syncify/schema/syncify.json"
197
+ }
198
+ ]
199
+ }
200
+ ```
201
+
202
+ # Configuration
203
+
204
+ Syncify supports `syncify.config.js` and `package.json` configurations. Depending on your preference, either option suffices and no restrictions are imposed. If you are defining options within your projects `package.json` file you can assign options on the `syncify` property.
205
+
206
+ ### Supported Files
207
+
208
+ - `syncify.config.js`
209
+ - `syncify.config.ts`
210
+ - `syncify.config.mjs`
211
+ - `syncify.config.cjs`
212
+ - `syncify.config.json`
213
+
214
+ ### Default Options
215
+
216
+ <!-- prettier-ignore -->
217
+ ```ts
218
+ import { defineConfig } from '@syncify/syncify';
219
+
220
+ export default defineConfig({
221
+ input: 'source',
222
+ output: 'theme',
223
+ export: 'export',
224
+ import: 'import',
225
+ config: '.',
226
+ clean: true,
227
+ stores: [
228
+ {
229
+ domain: '',
230
+ themes: {}
231
+ }
232
+ ],
233
+ hot: {
234
+ label: 'visible',
235
+ method: 'hot',
236
+ inject: true,
237
+ scroll: 'preserved',
238
+ server: 3000,
239
+ socket: 8089,
240
+ layouts: [
241
+ 'theme.liquid'
242
+ ],
243
+ },
244
+ logger: {
245
+ clear: true,
246
+ silent: false,
247
+ stats: true,
248
+ warnings: true
249
+ },
250
+ paths: {
251
+ redirects: 'redirects.yaml',
252
+ assets: 'assets/**/*',
253
+ files: 'files/**/*',
254
+ config: 'config/*.json',
255
+ locales: 'locales/*.json',
256
+ layout: 'layouts/*.liquid',
257
+ sections: 'sections/*.liquid',
258
+ snippets: 'snippets/*.liquid',
259
+ metafields: 'metafields/**/*.json',
260
+ customers: [
261
+ 'templates/customers/*.json',
262
+ 'templates/customers/*.liquid'
263
+ ],
264
+ pages: [
265
+ 'pages/*.md',
266
+ 'pages/*.html'
267
+ ],
268
+ templates: [
269
+ 'templates/*.json',
270
+ 'templates/*.liquid'
271
+ ],
272
+ },
273
+ spawn: {
274
+ build: {},
275
+ watch: {},
276
+ },
277
+ views: {
278
+ snippets: {
279
+ prefixDir: false,
280
+ separator: '-',
281
+ global: []
282
+ },
283
+ sections: {
284
+ prefixDir: false,
285
+ separator: '-',
286
+ global: []
287
+ },
288
+ pages: {
289
+ suffixDir: true,
290
+ author: '',
291
+ global: [],
292
+ language: [
293
+ 'html',
294
+ 'markdown'
295
+ ],
296
+ }
297
+ },
298
+ plugins: []
299
+ });
300
+ ```
301
+
302
+ # Getting Started
303
+
304
+ It is relatively easy to get started developing Shopify themes using Syncify. If you are converting an existing project and using Theme Kit or another build environment you can progressively adapt it into your workflow by manually configuring how Syncify should behave. Whatever the case, have a look at the [Dusk](#) theme in the [Syncify Examples](#) repository. Dusk is the Shopify [Dawn](#) theme using Syncify instead of Theme Kit and provides developers a great starting point for new projects.
305
+
306
+ ### Pre-requisites
307
+
308
+ Before going over the features Syncify provides, it is assumed that you have done the following:
309
+
310
+ 1. Installed Syncify as a development Dependency
311
+ 2. Created a private app and added API credentials
312
+ 3. Added a `syncify.config.ts` file in the root of your project
313
+
314
+ ### Contents
315
+
316
+ - [Directories](#directories)
317
+ - [Paths](#dirs)
318
+ - [Stores](#stores-required)
319
+ - [Hot](#hot)
320
+ - [Spawn](#spawn)
321
+ - [Views](#views)
322
+ - [Transforms](#views)
323
+ - [Processors](#views)
324
+ - [Minify](#views)
325
+
326
+ ## Directories
327
+
328
+ In Syncify you define custom base directories for your theme files. The values you define refers to a directory name which is relative to the root of your project and you **cannot** define multi-level directories (eg: `some/dir`) or reverse paths (eg: `../dir`).
329
+
330
+ <!-- prettier-ignore -->
331
+ <table>
332
+ <thead>
333
+ <tr>
334
+ <th width="500px">API</th>
335
+ <th width="500px">CLI</th>
336
+ </tr>
337
+ </thead>
338
+ <tbody>
339
+ <tr>
340
+ <td>
341
+
342
+ <!-- prettier-ignore -->
343
+ ```json
344
+ {
345
+ "input": "source",
346
+ "output": "theme",
347
+ "import": "import",
348
+ "export": "export",
349
+ "config": "."
350
+ }
351
+ ```
352
+
353
+ </td>
354
+ <td height="200px">
355
+
356
+ <!-- prettier-ignore -->
357
+ ```bash
358
+ --input -i # source
359
+ --output -o # theme
360
+ --config -c # config
361
+ --export -e # config
362
+ ```
363
+
364
+ </td>
365
+ </tr>
366
+
367
+ </tbody>
368
+ </table>
369
+
370
+ ### Input > Output
371
+
372
+ Syncify expects projects to have an **input** directory path which contains theme **source** files. Files contained within an input directory are written to your defined **output** directory path. The generated output will be reflective of your online store and in most cases you will add the output directory to your `.gitignore` file because it can rebuilt from input.
373
+
374
+ If you are used to working from a single directory (e.g: Dawn) then it is important that you understand the difference between the **input** and **output** directories.
375
+
376
+ # Stores (Required)
377
+
378
+ The `stores` option accepts an **object** or **array** type. Each item will hold a settings object that contains references to your shopify store/s and their theme/s. For each store you define, Syncify requires you provide the shop name and theme id/s you wish to sync. The `themes` object uses a **key** > **value** structure.
379
+
380
+ > Please see theme [commands](#commands) example for more information on how this is used with the CLI.
381
+
382
+ ### CLI
383
+
384
+ ```bash
385
+ --theme, -t <target> # theme targeting
386
+ ```
387
+
388
+ ### API
389
+
390
+ ```ts
391
+ import { defineConfig } from '@syncify/syncify';
392
+
393
+ export default defineConfig({
394
+ stores: [
395
+ {
396
+ domain: 'shop-1', // equivalent of shop-1.myshopify.com
397
+ themes: {
398
+ dev: 123456789,
399
+ prod: 123456789,
400
+ stage: 123456789,
401
+ test: 123456789
402
+ }
403
+ }
404
+ ]
405
+ });
406
+ ```
407
+
408
+ <details>
409
+ <summary>
410
+ <strong><code>Domain</code></strong>
411
+ </summary>
412
+ <p>
413
+
414
+ The `domain` option expects a string value, which is your Shopify store name without the `myshopify.com` portion. The domain will be used by the CLI as a target reference argument. Each store (domain) can have multiple themes.
415
+
416
+ </p>
417
+ </details>
418
+
419
+ <details>
420
+ <summary>
421
+ <strong><code>Themes</code></strong>
422
+ </summary>
423
+ <p>
424
+
425
+ The `themes` option refers to theme ids the store contains. This option is an object type which uses **key** > **value** mappings. The theme **keys** represent a unique target name, this can be any alpha numeric value. The **key** value will be used by the CLI as target names. The **value** should be the theme id.
426
+
427
+ </p>
428
+ </details>
429
+
430
+ # Metafields
431
+
432
+ The `metafields` directory `path` reference is where you can provide **global** JSON metafield files that can be synced to your Shopify store. Metafield sync capabilities provided by Syncify use a simple **directory** > **file** based approach. The sub-directory names represent a metafield `namespace` value and JSON file names contained within represent metafield `key` values.
433
+
434
+ > Syncify will keep your remote and local metafield references aligned with one another and warn you when local versions do not match remote versions. This will help prevent you from overwriting changes that may have been applied by third-party apps or online within your store.
435
+
436
+ **Pull Metafields**
437
+
438
+ Syncify provides you with simple interactive prompt based approach for importing pre-existing metafields from your online store. You can optionally choose which metafields you'd like to maintain. Use the `-m` or `--metafields` flag together with the `--pull` flag on the command line to download metafields:
439
+
440
+ ```
441
+ $ syncify -m --pull
442
+ ```
443
+
444
+ **Merge Metafields**
445
+
446
+ Working with metafields from your local machine may have result in unexpected overwrites if changes were made to remote versions that conflict with local versions. In order to combat this Syncify support **merge** capabilities which can be used to merge changes when metafield modification timestamps differ. Use the `-m` or `--metafields` flag together with the `--merge` flag on the command line perform local and remote alignments.
447
+
448
+ ```
449
+ $ syncify -m --merge
450
+ ```
451
+
452
+ **Structure**
453
+
454
+ In order to best illustrate how the metafield sync capabilities work it is important that you understand the structure logic. The directory based approach and naming conventions employed are imperative and strict. Syncify wants to prevent irreversible overwrites or deletions from occurring, so please be mindful and wary when using this feature.
455
+
456
+ <table>
457
+ <thead>
458
+ <tr>
459
+ <th align="left" width="300px">&nbsp;&nbsp;&nbsp;&nbsp;Metafield Structure</th>
460
+ <th align="left" width="700px">&nbsp;&nbsp;&nbsp;&nbsp;Description</th>
461
+ </tr>
462
+ </thead>
463
+ <tbody>
464
+ <td>
465
+ <pre>
466
+ <code>
467
+ source
468
+
469
+ └── metafields
470
+
471
+ ├── garment
472
+ │ ├── fits.json
473
+ │ ├── sizes.json
474
+ │ └── fabrics.json ㅤㅤ ㅤㅤ ㅤㅤ
475
+
476
+ └── details
477
+ ├── colors.json
478
+ └── weight.json
479
+ </code>
480
+ </pre>
481
+ </td>
482
+ <td>
483
+ &nbsp;&nbsp;&nbsp;Metafields will be published to the global <code>shop</code> object.<br>
484
+ &nbsp;&nbsp;&nbsp;Syncify will use the sub-directory names as the metafield<br>
485
+ &nbsp;&nbsp;&nbsp;<code>namespace</code> and the JSON file names contained within<br>
486
+ &nbsp;&nbsp;&nbsp;each namespace directory are used as the metafield <code>key</code> name.<br><br>
487
+ <strong>Example:</strong><br><br>
488
+ <ul>
489
+ <li><code>{{ shop.metafields.garment.fits.value }}</code></li>
490
+ <li><code>{{ shop.metafields.garment.sizes.value }}</code></li>
491
+ <li><code>{{ shop.metafields.garment.fabrics.value }}</code></li>
492
+ <li><code>{{ shop.metafields.details.colors.value }}</code></li>
493
+ <li><code>{{ shop.metafields.details.weight.value }}</code></li>
494
+ </ul>
495
+ </td>
496
+ </tr>
497
+ </tbody>
498
+ </table>
499
+
500
+ ### Options
501
+
502
+ <details>
503
+ <summary>
504
+ <strong><code>Input</code></strong>
505
+ </summary>
506
+ <p>
507
+
508
+ The `input` option refers to your projects **src** location This is the directory where your development theme files exist. Syncify defaults this directory to `source`. The value defined here will be prepended to any path you define within `paths`.
509
+
510
+ </p>
511
+ </details>
512
+
513
+ <details>
514
+ <summary>
515
+ <strong><code>Output</code></strong>
516
+ </summary>
517
+ <p>
518
+
519
+ The `output` option refers to your project **dist** location. This is the directory where transformed theme files from `input` will be written. Syncify defaults this to `theme`. The `output` directory will be reflective of your online shop. You should point any asset files executing via spawned processes to the `assets` directory contained within this location.
520
+
521
+ </p>
522
+ </details>
523
+
524
+ <details>
525
+ <summary>
526
+ <strong><code>Config</code></strong>
527
+ </summary>
528
+ <p>
529
+
530
+ The `config` option refers to a directory within your project where configuration files exist, like (for example) a `rollup.config.js` or `webpack.config.js` file. Syncify by default (when this option is **undefined**) will look for config files in the root of your project but this might not always be ideal as it can create clutter in the workspace. The `config` directory allows you to optionally place spawned config files within a sub-directory and informs Syncify to look for these files from that location.
531
+
532
+ > Typically this is directory is named `scripts` in node projects.
533
+
534
+ </p>
535
+ </details>
536
+
537
+ <details>
538
+ <summary>
539
+ <strong><code>Import</code></strong>
540
+ </summary>
541
+ <p>
542
+
543
+ The `import` option refers to a directory where downloaded themes will be written. Syncify provides the ability to download themes from your online store and it is within this directory the files are created.
544
+
545
+ </p>
546
+ </details>
547
+
548
+ <details>
549
+ <summary>
550
+ <strong><code>Export</code></strong>
551
+ </summary>
552
+ <p>
553
+
554
+ The `export` option refers to a directory where packaged (`.zip`) themes will be written when running the `package` command. Packaged themes will be prepended with the version number defined in the projects `package.json` file.
555
+
556
+ </p>
557
+ </details>
558
+
559
+ <details>
560
+ <summary>
561
+ <strong><code>Metafields</code></strong>
562
+ </summary>
563
+ <p>
564
+
565
+ The `metafields` option refers to a directory within your project which can contain global JSON metafield files. The path location you reference here should point to a directory of sub-directories. Please refer to the [Metafields](#metafields) section for more information.
566
+
567
+ **Correct**
568
+
569
+ ```
570
+ {
571
+ "dirs": {
572
+ "metafields": "source/metafields"
573
+ }
574
+ }
575
+ ```
576
+
577
+ **Invalid**
578
+
579
+ ```
580
+ {
581
+ "dirs": {
582
+ "metafields": "source/metafields/**/*.json"
583
+ }
584
+ }
585
+ ```
586
+
587
+ </p>
588
+ </details>
589
+
590
+ # Paths
591
+
592
+ The `paths` option allows you to define a custom set of path locations which point to theme specific files contained within the defined `input` directory. Syncify does not require you set a development structure consistent with that required by Shopify in your **input** because files are re-routed to the standard theme structure upon generating the **output**. Each path option accepts either a `string` or `string[]` array list of glob [anymatch](https://www.npmjs.com/package/anymatch) patterns. Paths will automatically resolve to the `input` directory, so you do not need to include it within your mapping.
593
+
594
+ ### API
595
+
596
+ By default, Syncify assumes you are using the basic-bitch (default) structure as followed:
597
+
598
+ <!-- prettier-ignore -->
599
+ ```ts
600
+ import { defineConfig } from '@syncify/syncify';
601
+
602
+ export default defineConfig({
603
+ input: 'source',
604
+ output: 'theme',
605
+ paths: {
606
+ assets: 'assets/**',
607
+ config: 'config/*.json',
608
+ locales: 'locales/*.json',
609
+ layout: 'layout/.liquid',
610
+ metafields: 'metafields/**/*.json',
611
+ sections: 'sections/*.liquid',
612
+ snippets: 'snippets/*.liquid',
613
+ templates: 'templates/*.liquid',
614
+ customers: 'templates/customers/*',
615
+ pages: 'pages/*',
616
+ redirects: 'redirects.yaml',
617
+ }
618
+ })
619
+ ```
620
+
621
+ ### Custom Structures
622
+
623
+ Below are **2** different **input** structures and an **output** structure. The **default structure** is what Syncify will use (as above) if no `paths` have been defined in your configuration, the tool defaults to this. The **customized structure** is an example of how you _could_ arrange an `input` directory using the Syncify `paths` option. The **output structure** is what Syncify will generated as an **output** which Shopify understands.
624
+
625
+ <table>
626
+ <thead>
627
+ <tr>
628
+ <th width=330px>Default Structure</th>
629
+ <th width="330px">Customized Structure</th>
630
+ <th width="330px">Output Structure</th>
631
+ </tr>
632
+ </thead>
633
+ <tbody>
634
+ <td>
635
+ <pre>
636
+ <code>
637
+
638
+
639
+
640
+ source
641
+ └─┐
642
+ ├─ assets
643
+ ├─ config
644
+ ├─ layout
645
+ ├─ locales
646
+ ├─ pages
647
+ ├─ metafields
648
+ │ └─ namespace
649
+ │ └─ key.json ㅤ
650
+ ├─ sections
651
+ ├─ snippets
652
+ └─ templates
653
+ └─ customers
654
+
655
+
656
+
657
+ </code>
658
+ </pre>
659
+ </td>
660
+ <td>
661
+ <pre>
662
+ <code>
663
+ source
664
+ └─┐
665
+ ├── assets
666
+ │ ├─ files
667
+ │ ├─ icons
668
+ │ └─ images
669
+ ├─ data
670
+ │ ├─ config
671
+ │ ├─ locales
672
+ │ └─ metafields
673
+ │ └─ namespace
674
+ │ └─ key.json ㅤ
675
+ ├─ styles
676
+ ├─ scripts
677
+ └─ views
678
+ ├─ customers
679
+ ├─ sections
680
+ ├─ snippets
681
+ ├─ templates
682
+ └─ theme.liquid
683
+ </code>
684
+ </pre>
685
+ </td>
686
+ <td>
687
+ <pre>
688
+ <code>
689
+ ㅤㅤ
690
+
691
+ ㅤ ㅤ
692
+ ㅤ ㅤ
693
+ ㅤ ㅤ
694
+
695
+ output
696
+ └─┐
697
+ ├─ assets
698
+ ├─ config
699
+ ├─ locales
700
+ ├─ layout
701
+ ├─ sections
702
+ ├─ snippets
703
+ └─ template
704
+ └─ customers ㅤ
705
+
706
+
707
+
708
+
709
+ </code>
710
+ </pre>
711
+ </td>
712
+ </tr>
713
+ </tbody>
714
+ </table>
715
+
716
+ There is no distributed difference between the **default** and **customized** structures illustrated above. Both would generate an **output** that Shopify understands, requires and reasons with. Only the **input** source locations differ. The **output** Syncify creates will always be written to a standard Shopify theme structure regardless of how you may decide to organize **input** paths.
717
+
718
+ ### Options
719
+
720
+ <details>
721
+ <summary>
722
+ <strong><code>Assets</code></strong>
723
+ </summary>
724
+ <p>
725
+
726
+ An array list of glob path patterns for **asset** files. These will be written in the `assets` directory of your defined `output` path. Please note that you if you transforming CSS, SCSS, SASS or SVG file types using Syncify then you do not need to define those paths here as the `transforms` option will automatically route them, this is the same for assets being processed by spawns.
727
+
728
+ **Understanding Spawns in watch mode**
729
+
730
+ Syncify will automatically set watch paths of assets when running in watch mode. It will glob match all files being written to your defined `{output}/assets` path but exclude those which you have set to be handled or transformed. For example, if you are using a JavaScript bundler like webpack of rollup, Syncify will watch for any files that are written and handled by these tools or any other spawned process for that matter and once written will trigger an upload.
731
+
732
+ </p>
733
+ </details>
734
+
735
+ <details>
736
+ <summary>
737
+ <strong><code>Customers</code></strong>
738
+ </summary>
739
+ <p>
740
+
741
+ An array list of glob path patterns to `.liquid` or `.json` **customer** template files. These will be written to the `{output}/templates/customers` directory of your defined `output` path.
742
+
743
+ </p>
744
+ </details>
745
+
746
+ <details>
747
+ <summary>
748
+ <strong><code>Locales</code></strong>
749
+ </summary>
750
+ <p>
751
+
752
+ An array list of glob path patterns to `.json` **locale** files. These will be written to the `{output}/locales` directory of your defined `output` path.
753
+
754
+ </p>
755
+ </details>
756
+
757
+ <details>
758
+ <summary>
759
+ <strong><code>Config</code></strong>
760
+ </summary>
761
+ <p>
762
+
763
+ An array list of glob path patterns to `.json` **config** files. These will be written to the `{output}/config` directory of your defined `output` path.
764
+
765
+ </details>
766
+
767
+ <details>
768
+ <summary>
769
+ <strong><code>Layout</code></strong>
770
+ </summary>
771
+ <p>
772
+
773
+ An array list of glob path patterns to `.liquid` **layout** files. These will be written to the `{output}/layout` directory of your defined `output` path.
774
+
775
+ </p>
776
+ </details>
777
+
778
+ <details>
779
+ <summary>
780
+ <strong><code>Sections</code></strong>
781
+ </summary>
782
+ <p>
783
+
784
+ An array list of glob path patterns to `.liquid` **section** files. These will be written to the `sections` directory of your defined `output` path. Sections can be structured within sub-directories. If a section file is determined to be deeply nested in such a way then this option will enable parent directory name prefixing to be applied the output filenames.
785
+
786
+ **Understanding Section Processing**
787
+
788
+ If the section input path is `source/sections/index/some-file.liquid` then the filename will be prefixed with `index` so when referencing it within themes you'd need to use `index-some-file.liquid` in `{% section %}` tags. Prefixing is helpful when you have a large number of sections and want to avoid name collusion.
789
+
790
+ See also [Views](#views).
791
+
792
+ </p>
793
+
794
+ </details>
795
+
796
+ <details>
797
+ <summary>
798
+ <strong><code>Snippets</code></strong>
799
+ </summary>
800
+ <p>
801
+
802
+ An array list of glob path patterns to `.liquid` **snippet** files. These will be written to the `snippets` directory of your defined `output` path.
803
+
804
+ See also [Views](#views).
805
+
806
+ </p>
807
+ </details>
808
+
809
+ <details>
810
+ <summary>
811
+ <strong><code>Templates</code></strong>
812
+ </summary>
813
+ <p>
814
+
815
+ An array list of glob path patterns to `.json` or `.liquid` **template** files. These will be written to the `templates` directory of your defined `output` path.
816
+
817
+ </p>
818
+ </details>
819
+
820
+ # HOT
821
+
822
+ Live reloading is supported in watch mode. Syncify leverages websocket's, XHR and statically served endpoints to provide this capability with zero configuration or the need to install or setup additional tooling. No extensions and no complexities. When you invoke `--hot` syncify will listen for messages sent via websocket on the client and carry out HOT replacements of Assets, Sections, Snippets, Layouts and Templates without triggering full-page refreshes. Syncify's HOT reloads are considerably faster than Shopify's CLI and will never invoke a full-page refresh.
823
+
824
+ ### Assets
825
+
826
+ SASS/CSS, TypeScript/JavaScript and SVG asset file types are HOT reloaded by swapping out the URL's or containing source with localhost equivalents that Syncify will statically serve.
827
+
828
+ ### Sections
829
+
830
+ Sections are fetched via the Ajax Section rendering API. Replacements are applied to fragments in real-time.
831
+
832
+ ### Snippets, Layouts and Templates
833
+
834
+ In order to provide HOT replacements Syncify employs a mild form of DOM hydration. Snippets, templated and liquid layout files will inject HTML comments `<!-- hot:1aa4f32cf9 -->` containing a UUID before they are uploaded to themes. Syncify will pass this UUID to the client via websocket and once received an XHR (fetch) will be triggered. The response of the XHR request is then parsed and all nodes which proceed the injected UUID comment/s are plucked and swapped in the persisted DOM while leaving unchanged elements intact. The approach employed by Syncify is a mild form DOM hydration that's 10x faster than invoking a hard-refresh.
835
+
836
+ # Spawn
837
+
838
+ The spawn option accepts a **key** > **value** list of commands (ie: scripts) which you can be used when we are running `watch` or `build` modes. Spawn allows you to leverage additional build tools and have them execute in parallel with Syncify. Spawned processes allow you use your preferred asset bundlers, like [Rollup](#), [Webpack](#), [Gulp](#) and many more without having to run multiple npm-scripts.
839
+
840
+ ### Overview
841
+
842
+ There are 2 available modes from which you can trigger a spawned process. When a process is spawned in `watch` mode it will run along side Syncify in parallel and execute sequentially in the order of which each spawn is defined. You need to provide any --flags your command (build tool or bundler) requires when running. Spawning a process in `build` mode will trigger spawned commands only 1 time, so it is here where you would provide the compile-only or build-only command, ie: not using watch flags/arguments.
843
+
844
+ The Syncify **build** mode re-builds the entire theme and you might choose to run this mode using the Syncify `--prod` flag, if you require context of the environment, mode or action taking place within spawned config files, then take a look at the available [Utilities](#utilities) Syncify exposes to help you conditionally load plugins or trigger different build types in accordance with Syncify.
845
+
846
+ ### CLI
847
+
848
+ ```bash
849
+ --spawn, -s <name> # spawn targeting
850
+ ```
851
+
852
+ ### API
853
+
854
+ <!-- prettier-ignore -->
855
+ ```ts
856
+ import { defineConfig } from '@syncify/syncify';
857
+
858
+ export default defineConfig({
859
+ spawn: {
860
+ build: {},
861
+ watch: {}
862
+ }
863
+ }
864
+ })
865
+ ```
866
+
867
+ ## Usage
868
+
869
+ In most situations you will leverage the spawn option to compile TypeScript or JavaScript assets, but it is important to note that this capability is not specific to these assets types. Syncify is using [cross-spawn](https://www.npmjs.com/package/cross-spawn) under the hood to help negate any cross-platform issues that may arise. Please note that all stdout/stderr/stdio from spawned processes will be piped through and intercepted by Syncify, which might result in output being stripped of color. Below are a couple examples where we spawn up 2 well known JavaScript bundlers and lastly we illustrate how to spawn multiple processes.
870
+
871
+ ### Rollup Example
872
+
873
+ If you are processing JavaScript asset files using the [Rollup](https://rollupjs.org/) bundler you can spawn build and watch processes by providing the rollup commands to each mode accordingly. Rollup is a fantastic choice for handling `.js` files and is the preferred option for processing these asset types. In this example, it is assumed that a `rollup.config.js` file is located in the root of your project.
874
+
875
+ <!-- prettier-ignore -->
876
+ ```ts
877
+ import { defineConfig } from '@syncify/syncify';
878
+
879
+ export default defineConfig({
880
+ spawn: {
881
+ build: {
882
+ rollup: 'rollup -c'
883
+ },
884
+ watch: {
885
+ rollup: 'rollup -c -w'
886
+ }
887
+ }
888
+ }
889
+ })
890
+ ```
891
+
892
+ ### Webpack Example
893
+
894
+ If you are processing JavaScript asset files using the [Webpack](https://webpack.js.org/) bundler you can spawn build and watch processes by providing the webpack commands to each mode accordingly. You will need to be using the [Webpack CLI](https://github.com/webpack/webpack-cli) module to ensure a successful spawn is triggered.
895
+
896
+ > Notice how we also provide the `--color` flag in the spawn. If you omit this flag then the webpack logs will be printed to the CLI without colors, when using webpack you should provide this flag.
897
+
898
+ <!-- prettier-ignore -->
899
+ ```ts
900
+ import { defineConfig } from '@syncify/syncify';
901
+
902
+ export default defineConfig({
903
+ spawn: {
904
+ build: {
905
+ webpack: 'webpack --color'
906
+ },
907
+ watch: {
908
+ webpack: 'webpack --watch --color'
909
+ }
910
+ }
911
+ }
912
+ })
913
+ ```
914
+
915
+ ### Multiple Processes
916
+
917
+ Though it is unlikely you'd ever need to include 2 different JavaScript bundlers in a project there is nothing stopping you from doing such a thing. For the sake of brevity, the below example illustrates how we can execute multiple spawned child processes to run in parallel with Syncify. Notice how we have also included an additional **gulp** spawn in `build` and `watch` modes. Syncify will trigger these processes in sequentially order, Rollup (1), Gulp (2) and Webpack (3).
918
+
919
+ > Aside from attempting to spawn Syncify itself, there is no limitation or restrictions imposed on what you choose to run along side Syncify.
920
+
921
+ <!-- prettier-ignore -->
922
+ ```ts
923
+ import { defineConfig } from '@syncify/syncify';
924
+
925
+ export default defineConfig({
926
+ spawn: {
927
+ build: {
928
+ rollup: 'rollup -c',
929
+ webpack: 'webpack --color',
930
+ gulp: 'gulp watch-task'
931
+ },
932
+ watch: {
933
+ webpack: 'webpack --watch --color',
934
+ rollup: 'rollup -c -w',
935
+ gulp: 'gulp watch-task'
936
+ }
937
+ }
938
+ }
939
+ })
940
+ ```
941
+
942
+ # Transform
943
+
944
+ In Syncify, asset files can be transformed and augmented before being written to the defined `output` directory and uploaded to your Shopify store. The `transform` option allows you to control how your asset files are processed. Syncify supports built-in and partial processing for the following file types:
945
+
946
+ - `.json`
947
+ - `.js`
948
+ - `.ts`
949
+ - `.jsx`
950
+ - `.tsx`
951
+ - `.css`
952
+ - `.scss`
953
+ - `.sass`
954
+ - `.svg`
955
+
956
+ ## Scripts
957
+
958
+ Syncify exposes a `scripts` transform option which can be used as a convenience wrapped around the [tsup](https://tsup.egoist.sh/#what-can-it-bundle) bundler. TSUP uses the powerful [ESBuild](https://esbuild.github.io/) under the hood for processing TypeScript and JavaScript file types.
959
+
960
+ ## Styles
961
+
962
+ Syncify exposes a `styles` transform option which can be used as a convenience wrapper for handling `.css`, `.scss` or `.scss` asset files types. The **styles** option accepts an **array** list of style specific configurations that are used together with compilers like [Dart SASS](#) and [PostCSS](#). Style transforms help alleviate the complexities sometimes involved in setting up these tools so you can easily process and generate asset specific stylesheets that can be optionally inlined as a **snippet** file.
963
+
964
+ ### SASS Support
965
+
966
+ Syncify provides partial processing of `.scss` and `.sass` file types using [Dart SASS](#). If you require transform support for these files you need to install the Dart module as a development dependency in your project.
967
+
968
+ ```
969
+ pnpm add sass -D
970
+ ```
971
+
972
+ ### CSS Support
973
+
974
+ In addition to SASS transformation, Syncify also support CSS processing using [PostCSS](#). If you wish have Syncify handle CSS transforms then you need to install **PostCSS** as a development dependency and also include a `postcss.config.js` file in your project. Syncify expects you will inform upon how CSS files are to be handled within a `postcss.config.js` file and it will look for the existence of one within your workspace.
975
+
976
+ > Provide PostCSS plugins and any specific settings within the `postcss.config.js` file.
977
+
978
+ ```
979
+ pnpm add postcss -D
980
+ ```
981
+
982
+ **Please note:** If you are using Syncify to compile SASS files, then by default the transformed CSS will be passed to PostCSS. Use the available Syncify `style` options to disable this behavior.
983
+
984
+ ### Usage
985
+
986
+ In the below example we are generating multiple stylesheets and compiling both SCSS and CSS file types. The example illustrates how one can leverage Syncify together with [Dart SASS](#), [PostCSS](#) and additional node modules like the Bootstrap framework.
987
+
988
+ > **Please Note** You will need to remove the comments from the code example if you are copy and pasting it into your `package.json` file. JSON with Comments is not supported in `package.json` files.
989
+
990
+ <!-- prettier-ignore-->
991
+ ```ts
992
+ import { defineConfig } from '@syncify/syncify'
993
+
994
+ export default defineConfig({
995
+ transforms: {
996
+ script: {
997
+ 'assets/bundle.min.js': 'scripts/bundle.ts',
998
+ 'assets/mithril.min.js': 'scripts/virtual.ts',,
999
+ 'snippets/[dir]-[file]': ['scripts/globs/*.ts'],
1000
+ 'assets/globs.min.js': {
1001
+ input: 'scripts/globs.ts',
1002
+ format: 'iife'
1003
+ }
1004
+ },
1005
+ style: {
1006
+ 'assets/stylesheet.min.css': {
1007
+ input: 'styles/stylesheet.scss',
1008
+ watch: ['styles/sections/*'],
1009
+ postcss: true,
1010
+ sass: true
1011
+ },
1012
+ 'snippets/css.liquid': {
1013
+ input: 'styles/vars.css.liquid',
1014
+ postcss: true,
1015
+ sass: true
1016
+ },
1017
+ 'assets/bootstrap.min.scss': {
1018
+ input: 'styles/vendors/bootstrap.scss',
1019
+ style: 'expanded',
1020
+ includePaths: ['node_modules/bootstrap']
1021
+ }
1022
+ }
1023
+ }
1024
+ })
1025
+ ```
1026
+
1027
+ ## Views
1028
+
1029
+ The `views` transform option controls how `.liquid` file types should be handled. Snippets, Templates, Sections and Layout paths are typically where liquid files are used. Options defined here will be used when Syncify is processing such types.
1030
+
1031
+ ### Sections
1032
+
1033
+ Syncify provides sub-directory grouping and rename prefixing capabilities when handling theme sections. You might be accustom to storing sections within a single directory and despite Shopify using this approach in their Dawn theme, it is restrictive and rather chaotic to the developer experience. A far better approach is to take advantage of the sub-directory grouping feature which Syncify provides.
1034
+
1035
+ **Sub-directory Grouping**
1036
+
1037
+ Shopify shipped "sections everywhere" capabilities in Online Store 2.0 and while this is a great feature to have it opens the door to inconsistent structures. The logic of Shopify here has been to provide store developers "freedom" but it is a double edged sword. Sections everywhere has consequently resulted in developers indirectly facilitating merchants the ability to leverage sections on pages where they should otherwise be avoided. For instance, enabling merchants to add a featured-collection, featured-blog or full-screen hero image to product pages is not necessarily a good idea. Developers may be more inclined to provide such section types when working from within a single directory structure that is without organized order.
1038
+
1039
+ Shopify tends to push a DRY infrastructure approach for the theme development wherein store sections _should_ be capable of appropriation within any template. This is great in theory but in order to achieve aesthetic fluidity it is not realistic when we go beyond a Dawn structure and even there we find the utter chaos. Approaching things in a compartmentalized manner is just better approach but this is difficult when working from a single level structured directory.
1040
+
1041
+ Grouping section into sub-directories results is far better consideration, organization and order at the development level. Syncify provides these capabilities while still respecting developer personal preferences. Below is an example of how you can leverage Syncify to use sub-directories together with pre-fixing capabilities.
1042
+
1043
+ <!-- prettier-ignore -->
1044
+ <table>
1045
+ <thead>
1046
+ <tr>
1047
+ <th>Syncify Options</th>
1048
+ <th>Source Structure</th>
1049
+ <th>Theme Output</th>
1050
+ </tr>
1051
+ </thead>
1052
+ <tbody>
1053
+ <td>
1054
+
1055
+ <!-- prettier-ignore -->
1056
+ ```json
1057
+ {
1058
+ "paths": {
1059
+ "sections": [
1060
+ "sections/**/*"
1061
+ ]
1062
+ },
1063
+ "sections": {
1064
+ "prefix": true,
1065
+ "prefixSeparator": "-",
1066
+ "prefixDuplicates": true,
1067
+ "globals": [
1068
+ "shared",
1069
+ "layout",
1070
+ "related.liquid"
1071
+ ]
1072
+ }
1073
+ }
1074
+ ```
1075
+
1076
+ </code>
1077
+ </td>
1078
+ <td>
1079
+ <pre>
1080
+ <code>ㅤ
1081
+ source
1082
+
1083
+ └─ sections
1084
+ ├─ collection
1085
+ │ ├─ filter.liquid
1086
+ │ └─ search.liquid
1087
+ ├─ product
1088
+ │ ├─ images.liquid
1089
+ │ ├─ on-sale.liquid
1090
+ │ └─ related.liquid
1091
+ ├─ layout
1092
+ │ ├─ header.liquid
1093
+ │ └─ footer.liquid
1094
+ └─ shared
1095
+ ├─ banner.liquid
1096
+ └─ slideshow.liquid
1097
+ </code>
1098
+ </pre>
1099
+ </td>
1100
+ <td>
1101
+ <pre>
1102
+ <code>
1103
+
1104
+
1105
+ theme
1106
+
1107
+ └─ sections
1108
+ ├─ banner.liquid
1109
+ ├─ collection-filter.liquid
1110
+ ├─ collection-search.liquid
1111
+ ├─ footer.liquid
1112
+ ├─ header.liquid
1113
+ ├─ product-images.liquid
1114
+ ├─ product-on-sale.liquid
1115
+ ├─ related.liquid
1116
+ └─ slideshow.liquid
1117
+
1118
+
1119
+ </code>
1120
+ </pre>
1121
+ </td>
1122
+ </tr>
1123
+ </tbody>
1124
+ </table>
1125
+
1126
+ Notice how we can nest sections within sub-directories and also apply prefixing to the section output filenames. We also inform Syncify that some of our sections should be considered **global** and this allows those defined there to pass through without name augmentation (prefixing). We passed a `true` value to the `prefix` option, this informed Syncify that section files which are not explicitly defined as **global** should have their output filename prefixed with the **parent** directory name they are contained within.
1127
+
1128
+ <details>
1129
+ <summary>
1130
+ <strong><code>Sections</code></strong>
1131
+ </summary>
1132
+ <p>
1133
+
1134
+ **prefix**
1135
+
1136
+ **prefixDuplicates**
1137
+
1138
+ **prefixSeparator**
1139
+
1140
+ **globals**
1141
+
1142
+ </p>
1143
+ </details>
1144
+
1145
+ <details>
1146
+ <summary>
1147
+ <strong><code>Minify</code></strong>
1148
+ </summary>
1149
+ <p>
1150
+
1151
+ **env**
1152
+
1153
+ `never`
1154
+
1155
+ **minifyJS**
1156
+
1157
+ `boolean`
1158
+
1159
+ **minifyCSS**
1160
+
1161
+ `boolean`
1162
+
1163
+ **removeComments**
1164
+
1165
+ `boolean`
1166
+
1167
+ **collapseWhitespace**
1168
+
1169
+ `boolean`
1170
+
1171
+ **trimCustomFragments**
1172
+
1173
+ `boolean`
1174
+
1175
+ **ignoreCustomFragments**
1176
+
1177
+ `string[]`
1178
+
1179
+ **minifySectionSchema**
1180
+
1181
+ `boolean`
1182
+
1183
+ **removeLiquidComments**
1184
+
1185
+ `boolean`
1186
+
1187
+ **removeAttributeNewlines**
1188
+
1189
+ `boolean`
1190
+
1191
+ **removeRedundantDashTrims**
1192
+
1193
+ `boolean`
1194
+
1195
+ **ignoredLiquidTags**
1196
+
1197
+ `string[]`
1198
+
1199
+ **exclude**
1200
+
1201
+ `string[]`
1202
+
1203
+ </p>
1204
+ </details>
1205
+
1206
+ ### Json
1207
+
1208
+ The `json` transform option controls how `.json` files should be processed. Templates, Config, Locales and Metafields paths typically where JSON files are used. Options defined here will be used when Syncify is processing these file types. In addition, Syncify will also apply handle any Assets that have `.json` extension using these options.
1209
+
1210
+ <details>
1211
+ <summary>
1212
+ <strong><code>Spaces</code></strong>
1213
+ </summary>
1214
+ <p>
1215
+
1216
+ Beautification `2`
1217
+
1218
+ </p>
1219
+ </details>
1220
+
1221
+ <details>
1222
+ <summary>
1223
+ <strong><code>Minify</code></strong>
1224
+ </summary>
1225
+ <p>
1226
+
1227
+ Minification options
1228
+
1229
+ **env**
1230
+
1231
+ `never`
1232
+
1233
+ **removeSchemaRefs**
1234
+
1235
+ `true`
1236
+
1237
+ **exclude**
1238
+
1239
+ `string[]`
1240
+
1241
+ </p>
1242
+ </details>
1243
+
1244
+ ### Styles
1245
+
1246
+ The `styles` transform option accepts an array type. This option requires you have [Dart SASS](#) and/or [PostCSS](#) installed as a development dependencies in your project. Syncify supports the handling of `.sass`, `.scss` and `.css` file types using these tools and the options are convenience wrappers for them.
1247
+
1248
+ <details>
1249
+ <summary>
1250
+ <strong><code>Input</code></strong>
1251
+ </summary>
1252
+ <p>
1253
+
1254
+ Path `string[]` or `string`
1255
+
1256
+ </p>
1257
+ </details>
1258
+
1259
+ <details>
1260
+ <summary>
1261
+ <strong><code>Rename</code></strong>
1262
+ </summary>
1263
+ <p>
1264
+
1265
+ Rename Options
1266
+
1267
+ `string[]`
1268
+
1269
+ </p>
1270
+ </details>
1271
+
1272
+ <details>
1273
+ <summary>
1274
+ <strong><code>Watch</code></strong>
1275
+ </summary>
1276
+ <p>
1277
+
1278
+ Watch Options
1279
+
1280
+ `string[]`
1281
+
1282
+ </p>
1283
+ </details>
1284
+
1285
+ <details>
1286
+ <summary>
1287
+ <strong><code>Snippet</code></strong>
1288
+ </summary>
1289
+ <p>
1290
+
1291
+ `boolean`
1292
+
1293
+ </p>
1294
+ </details>
1295
+
1296
+ <details>
1297
+ <summary>
1298
+ <strong><code>PostCSS</code></strong>
1299
+ </summary>
1300
+ <p>
1301
+
1302
+ PostCSS options
1303
+
1304
+ **env**
1305
+
1306
+ `all`, `dev`, `prod` `never`
1307
+
1308
+ </p>
1309
+ </details>
1310
+
1311
+ <details>
1312
+ <summary>
1313
+ <strong><code>SASS</code></strong>
1314
+ </summary>
1315
+ <p>
1316
+
1317
+ **logWarnings**
1318
+
1319
+ `boolean`
1320
+
1321
+ **sourcemap**
1322
+
1323
+ `boolean`
1324
+
1325
+ **style**
1326
+
1327
+ `compressed` or `expanded`
1328
+
1329
+ </p>
1330
+ </details>
1331
+
1332
+ # Processors
1333
+
1334
+ Syncify can used together with different _third party_ preprocessor tooling and has built-in support that can be deferred to for handling. Using processors requires installing the relative module you'd like to leverage. This is an opt-in capability.
1335
+
1336
+ ### Script
1337
+
1338
+ - [ESBuild](#esbuild)
1339
+
1340
+ ### Svg
1341
+
1342
+ - [SVGO](#svgo)
1343
+ - [Sprite](#sprite)
1344
+
1345
+ ### Style
1346
+
1347
+ - [SASS](#sass)
1348
+ - [PostCSS](#postcss)
1349
+
1350
+ ### Image
1351
+
1352
+ - [Sharp](#sharp)
1353
+
1354
+ # ESBuild
1355
+
1356
+ Syncify provides integrated support with ESBuild for processing TypeScript, JavaScript, JSX and TSX file types. ESBuild provides wonderful capabilities like code splitting and tree shaking.
1357
+
1358
+ See also [Script Transforms](#).
1359
+
1360
+ ### Installation
1361
+
1362
+ Install ESBuild as a development dependency in your project:
1363
+
1364
+ ```bash
1365
+ pnpm add esbuild -D
1366
+ ```
1367
+
1368
+ ### Configuration
1369
+
1370
+ <!-- prettier-ignore -->
1371
+ ```ts
1372
+ {
1373
+ processors: {
1374
+ esbuild: {} // TSUP config options
1375
+ }
1376
+ }
1377
+ ```
1378
+
1379
+ # SASS
1380
+
1381
+ Syncify provides integrated support with SASS Dart for processing SASS/SCSS file types. Syncify implements its own handling when for usage with SASS and allows you to use it together with [PostCSS](#postcss).
1382
+
1383
+ See also [Style Transforms](#).
1384
+
1385
+ ### Installation
1386
+
1387
+ Install SASS as a development dependency in your project:
1388
+
1389
+ ```bash
1390
+ pnpm add sass -D
1391
+ ```
1392
+
1393
+ ### Configuration
1394
+
1395
+ <!-- prettier-ignore -->
1396
+ ```ts
1397
+ {
1398
+ processors: {
1399
+ sass: {} // SASS config options
1400
+ }
1401
+ }
1402
+ ```
1403
+
1404
+ # PostCSS
1405
+
1406
+ Syncify provides integrated support with PostCSS for processing CSS file types. You can leverage PostCSS together with the SASS processor for CSS files.
1407
+
1408
+ See also [Style Transforms](#).
1409
+
1410
+ ### Installation
1411
+
1412
+ Install PostCSS as a development dependency in your project:
1413
+
1414
+ ```bash
1415
+ pnpm add postcss -D
1416
+ ```
1417
+
1418
+ ### Configuration
1419
+
1420
+ <!-- prettier-ignore -->
1421
+ ```ts
1422
+ {
1423
+ processors: {
1424
+ postcss: [] // PostCSS plugins
1425
+ }
1426
+ }
1427
+ ```
1428
+
1429
+ # SVGO
1430
+
1431
+ Syncify provides integrated support with SVGO for processing SVG file types. If you would like to produce SVG Sprites, then you install [Spriter](#spriter) which uses SVGO under the hood.
1432
+
1433
+ See also [SVG Transforms](#) and [Icons Plugin](#).
1434
+
1435
+ ### Installation
1436
+
1437
+ Install SVGO as a development dependency in your project:
1438
+
1439
+ ```bash
1440
+ pnpm add svgo -D
1441
+ ```
1442
+
1443
+ ### Configuration
1444
+
1445
+ <!-- prettier-ignore -->
1446
+ ```ts
1447
+ {
1448
+ processors: {
1449
+ svgo: {} // SVGO config options
1450
+ }
1451
+ }
1452
+ ```
1453
+
1454
+ # Sprite
1455
+
1456
+ Syncify provides integrated support for creating SVG Sprites using Spriter (aka: SVG Sprite). SVG Sprite is a low level module that optimizes SVGs and bakes them into sprites that Syncify can inline and output.
1457
+
1458
+ See also [SVG Transforms](#) and [@syncify/icons-plugin](#).
1459
+
1460
+ ### Installation
1461
+
1462
+ Install Spriter as a development dependency in your project:
1463
+
1464
+ ```bash
1465
+ pnpm add svg-sprites -D
1466
+ ```
1467
+
1468
+ ### Configuration
1469
+
1470
+ <!-- prettier-ignore -->
1471
+ ```ts
1472
+ {
1473
+ processors: {
1474
+ sprite: {} // SVG Sprite config options
1475
+ }
1476
+ }
1477
+ ```
1478
+
1479
+ # Sharp
1480
+
1481
+ Syncify provides integrated support for convert large images in common formats to smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions using the Sharp.
1482
+
1483
+ See also [Image Transforms](#)
1484
+
1485
+ ### Installation
1486
+
1487
+ Install Sharp as a development dependency in your project:
1488
+
1489
+ ```bash
1490
+ pnpm add sharp -D
1491
+ ```
1492
+
1493
+ ### Configuration
1494
+
1495
+ <!-- prettier-ignore -->
1496
+ ```ts
1497
+ {
1498
+ processors: {
1499
+ sharp: {} // Sharp config options
1500
+ }
1501
+ }
1502
+ ```
1503
+
1504
+ # Minify
1505
+
1506
+ TODO
1507
+
1508
+ # CLI Usage
1509
+
1510
+ Syncify ships with a powerful command line interface that supports prompt execution. If you have installed Syncify globally, you can call `syncify` or `sync` from any project but you should avoid this and instead install the module as a development dependency on a per-project basis.
1511
+
1512
+ If you are using a package manager like [pnpm](https://pnpm.js.org/en/cli/install) you can simply call `pnpm syncify` (or `pnpm sync`) but if you are using npm or yarn then you may need to create reference script within your `package.json` file, eg:
1513
+
1514
+ ```json
1515
+ {
1516
+ "scripts": {
1517
+ "syncify": "syncify"
1518
+ }
1519
+ }
1520
+ ```
1521
+
1522
+ > If you are not using [pnpm](https://pnpm.js.org/en/cli/install) then you should really consider adopting it within your stack. It is a wonderful addition to any JavaScript project.
1523
+
1524
+ ### Commands
1525
+
1526
+ The Syncify CLI provides the following commands:
1527
+
1528
+ ```cli
1529
+ Default:
1530
+ syncify Starts interactive CLI command prompt
1531
+
1532
+ Aliases:
1533
+ sync An alias of syncify (can be used instead of syncify)
1534
+
1535
+ Commands:
1536
+ syncify Starts interactive CLI command prompt
1537
+ syncify <store> --flags Store name or comma separated list of stores and flags
1538
+
1539
+ Resource Flags:
1540
+ -t, --theme <targets> A comma separated list of theme targets
1541
+ -b, --build Triggers a build, use with upload to run build before uploading
1542
+ -w, --watch Starts watching for changes of files building when they occur
1543
+ -u, --upload Uploads theme to online store, use with -t to target theme
1544
+ -d, --download Downloads themes/s from specified stores
1545
+ -p, --package Package theme and export a .zip
1546
+ -m, --metafields Metafields resource mode
1547
+ -l, --locales Locales resource mode
1548
+ -s, --settings Settings resource mode
1549
+ -o, --output <path> A path value (used in download and build mode only)
1550
+ -h, --help, Prints command list and some help information
1551
+ -c, --clean, Removes all output files, use with --build to clean before bundling
1552
+ -q, --query <filter> Query online store data API, eg: themes, metafields assets
1553
+ -v, --version <action> Version control resource mode (see version arguments)
1554
+
1555
+ Version Arguments:
1556
+ patch Increments the package.json version patch, eg: 1.0.0 > 1.0.1
1557
+ minor Increments the package.json version minor, eg: 1.0.0 > 1.1.0
1558
+ major Increments the package.json version major, eg: 1.0.0 > 2.0.0
1559
+
1560
+ Operation Flags:
1561
+ --status Checks development environment and connections are valid.
1562
+ --pull Pull data from online store
1563
+ --merge Merge online data with local references
1564
+
1565
+ Generator Flags:
1566
+ --vsc Generates JSON schema spec for vscode users
1567
+
1568
+ Environment Flags:
1569
+ --dev, --development Run in development mode (default)
1570
+ --prod, --production Run in production mode
1571
+ ```
1572
+
1573
+ ### Example
1574
+
1575
+ CLI usage aims to be as simple as possible. A typical project will be targeting a single Shopify theme but you can target multiple themes and stores in seamless and productive manner. When targeting multiple stores or themes the CLI employs a flag based naming approach.
1576
+
1577
+ **Generate theme targets**
1578
+
1579
+ ```cli
1580
+ $ syncify store-name -q themes
1581
+ ```
1582
+
1583
+ Prompt interface will be initialized
1584
+
1585
+ 1. Target **store-name**
1586
+ 2. Initialize Query resource
1587
+ 3. Inform query we want the "themes" endpoint
1588
+
1589
+ **Generate local metafields**
1590
+
1591
+ ```cli
1592
+ $ syncify store-name -m --pull
1593
+ ```
1594
+
1595
+ Prompt interface will be initialized
1596
+
1597
+ 1. Target **store-name**
1598
+ 2. Initialize Metafields resource
1599
+ 3. Pull data from online-store
1600
+
1601
+ **Upload theme to online store**
1602
+
1603
+ ```cli
1604
+ $ syncify store-name -t theme-1,theme-2 -c -b -u --prod
1605
+ ```
1606
+
1607
+ Exchange interface will be initialized
1608
+
1609
+ 1. Target **store-name**
1610
+ 2. Theme targets are **theme-1** and **theme-2**
1611
+ 3. Trigger Clean
1612
+ 4. Trigger Build (production build because of --prod flag)
1613
+ 5. Trigger Upload
1614
+
1615
+ **Watching 1 store and 1 theme**
1616
+
1617
+ ```cli
1618
+ $ syncify shop -w -t dev
1619
+ ```
1620
+
1621
+ <details>
1622
+ <summary>
1623
+ Breakdown
1624
+ </summary>
1625
+
1626
+ The above command is calling `watch` on a store named `cool-shop` and will upload changes to a theme named `dev`. We are using the shorthand `--theme` flag (`-t`) to inform upon the theme we want changes uploaded.
1627
+
1628
+ </details>
1629
+
1630
+ <details>
1631
+ <summary>
1632
+ Configuration
1633
+ </summary>
1634
+
1635
+ The `package.json` configuration for the command would look like this:
1636
+
1637
+ ```jsonc
1638
+ {
1639
+ "syncify": {
1640
+ "stores": [
1641
+ {
1642
+ "domain": "cool-shop", // The store name
1643
+ "themes": {
1644
+ "dev": 123456789 // The theme id and target name
1645
+ }
1646
+ }
1647
+ ]
1648
+ }
1649
+ }
1650
+ ```
1651
+
1652
+ </details>
1653
+
1654
+ **Watching 1 store and 2 themes**
1655
+
1656
+ ```cli
1657
+ $ syncify shop -w -t dev,prod
1658
+ ```
1659
+
1660
+ <details>
1661
+ <summary>
1662
+ Breakdown
1663
+ </summary>
1664
+
1665
+ The above command is calling `watch` on a store named `my-shop` and will upload changes to 2 different themes in that store we have named `dev` and `prod`.
1666
+
1667
+ </details>
1668
+
1669
+ <details>
1670
+ <summary>
1671
+ Configuration
1672
+ </summary>
1673
+
1674
+ The `package.json` configuration for the command would look like this:
1675
+
1676
+ ```jsonc
1677
+ {
1678
+ "syncify": {
1679
+ "stores": [
1680
+ {
1681
+ "domain": "my-shop", // The store name
1682
+ "themes": {
1683
+ "dev": 123456789, // The theme id and target name
1684
+ "prod": 123456789 // The theme id and target name
1685
+ }
1686
+ }
1687
+ ]
1688
+ }
1689
+ }
1690
+ ```
1691
+
1692
+ </details>
1693
+
1694
+ **Watching 2 stores and multiple themes**
1695
+
1696
+ ```cli
1697
+ $ syncify shop1,shop2 -w --shop1=test --shop2=dev,stage,prod
1698
+ ```
1699
+
1700
+ <details>
1701
+ <summary>
1702
+ Breakdown
1703
+ </summary>
1704
+
1705
+ The above command is calling `watch` on 2 stores, `shop1` and `shop2`. We are targeting a theme named `test` in the store `shop1` and 3 different themes in `shop2` named `dev`, `stage` and `prod`. Syncify will upload changes to both store and all the defined themes. Notice how we target different store themes in the command using the store name as a flag.
1706
+
1707
+ </details>
1708
+
1709
+ <details>
1710
+ <summary>
1711
+ Configuration
1712
+ </summary>
1713
+
1714
+ The `package.json` configuration for the command would look like this:
1715
+
1716
+ ```json
1717
+ {
1718
+ "syncify": {
1719
+ "stores": [
1720
+ {
1721
+ "domain": "shop1", // The store name
1722
+ "themes": {
1723
+ "test": 123456789 // The theme id and target name
1724
+ }
1725
+ },
1726
+ {
1727
+ "domain": "shop2", // The store name
1728
+ "themes": {
1729
+ "dev": 123456789,
1730
+ "stage": 123456789,
1731
+ "prod": 123456789
1732
+ }
1733
+ }
1734
+ ]
1735
+ }
1736
+ }
1737
+ ```
1738
+
1739
+ </details>
1740
+
1741
+ ### Prompts
1742
+
1743
+ Syncify provides a helpful command prompt feature. Running `syncify` will provide you a simple prompt interface from which you can use to explore endpoints directly from your CLI or trigger commands.
1744
+
1745
+ **Options**
1746
+
1747
+ **Queries**
1748
+
1749
+ # API
1750
+
1751
+ Syncify can be initialized within scripts. This approach is a little more feature-full and allows you to integrate it with different build tools. You can hook into the transit process of files and apply modifications before they are uploaded to your store/s with this approach.
1752
+
1753
+ ### Usage
1754
+
1755
+ Syncify exports a function that has several methods which you can use to trigger specific modes. The default export can also target multiple hooks in accordance with what was passed from the command line.
1756
+
1757
+ ```typescript
1758
+ import { syncify } from '@liquify/syncify';
1759
+
1760
+ // Build hook
1761
+ syncify.build(options: {}, async function(content?: Buffer): Promise<Buffer|string|void|false>);
1762
+
1763
+ // Watch hook
1764
+ syncify.watch(options: {}, async function(content?: Buffer): Promise<Buffer|string|void|false>);
1765
+
1766
+ // Upload hook
1767
+ syncify.upload(options: {}, async function(content?: Buffer): Promise<Buffer|string|void|false>);
1768
+
1769
+ // Download hook
1770
+ syncify.download(options: {}, async function(content?: Buffer): Promise<Buffer|string|void|false>);
1771
+
1772
+ // Targeting all hooks
1773
+ syncify(options: {})({
1774
+ async build(content?: Buffer): Promise<Buffer|string|void|false>,
1775
+ async watch(content?: Buffer): Promise<Buffer|string|void|false>,
1776
+ async upload(content?: Buffer): Promise<Buffer|string|void|false>,
1777
+ async download(content?: Buffer): Promise<Buffer|string|void|false>,
1778
+ });
1779
+
1780
+ ```
1781
+
1782
+ ### Utilities
1783
+
1784
+ Utilities will return some basic information about the Syncify instance. These are extremely helpful when when you are executing spawned processes and need to control what feature to load. For example, if you are spawning a webpack process for compiling JavaScript assets and need to inform upon watch mode you'd use `util.resource('watch')` which returns a boolean value when running in watch mode.
1785
+
1786
+ ```typescript
1787
+ import { util, env } from 'shopify-sync'
1788
+
1789
+ // Environment Conditions
1790
+ env.prod: boolean;
1791
+ env.dev: boolean;
1792
+ env.build: boolean;
1793
+ env.watch: boolean;
1794
+ env.download: boolean;
1795
+ env.upload: boolean;
1796
+
1797
+ // Returns environment
1798
+ util.env('dev' | 'prod'): boolean
1799
+
1800
+ // Returns the current resource
1801
+ util.mode('build' | 'watch' | 'upload' | 'download'): boolean
1802
+
1803
+ // Returns spawns
1804
+ util.spawned(): string[]
1805
+
1806
+ ```
1807
+
1808
+ ### Backwards Compatibility
1809
+
1810
+ Syncify supports backward compatibility for [shopify-sync](https://github.com/panoply/shopify-sync). This allows you to use it as you would have in earlier versions with build tools like [Gulp](https://gulpjs.com).
1811
+
1812
+ > Please note this support for this will eventually be deprecated.
1813
+
1814
+ ```typescript
1815
+ import { shopifysync as sync } from '@liquify/syncify';
1816
+
1817
+ // Backward compatible, ie: shopify-sync
1818
+ sync(mode: string, options: {}, function() {})
1819
+
1820
+ ```
1821
+
1822
+ # Contributing
1823
+
1824
+ This project uses [pnpm](https://pnpm.js.org/en/cli/install). Fork the project, run `pnpm i` and you're good to go. If you're using Yarn like the rest of the plebs or npm then you will still need to install pnpm.
1825
+
1826
+ # Author
1827
+
1828
+ Created by [Nίκος Σαβίδης](https://github.com/panoply) of [Sissel ΣaaΣ](https://sissel.io).
1829
+
1830
+ ### Acknowledgements
1831
+
1832
+ Special thanks to a couple of talented developers that helped work through ideas and edge-cases on the project.
1833
+
1834
+ - [Joseph Curtis](#)
1835
+ - [David Warrington](https://ellodave.dev/)
1836
+ - [Mansedan](#)
1837
+
1838
+ # Changelog
1839
+
1840
+ Refer to the [Changelog](changelog.md) for each per-version update and/or fixes.