├── .all-contributorsrc ├── .cz-config.js ├── .editorconfig ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── 1-bug.md │ ├── 2-feature.md │ ├── 3-discussion.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── e2e.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── cli-usage │ │ ├── executors │ │ │ ├── build.md │ │ │ ├── deploy.md │ │ │ ├── serve.md │ │ │ └── test.md │ │ └── generators │ │ │ ├── layout.md │ │ │ ├── section.md │ │ │ ├── snippet.md │ │ │ └── template.md │ ├── fundamentals │ │ ├── creating-a-theme.md │ │ ├── theme-bootstrap.md │ │ └── theme-structure.md │ ├── guides │ │ ├── environments.md │ │ ├── extend-webpack.md │ │ ├── liquid-in-styles.md │ │ ├── liquid-to-ts-context.md │ │ └── using-react.md │ ├── installation.md │ ├── introduction.md │ └── md-ref.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.js │ │ └── styles.module.css ├── static │ ├── .nojekyll │ └── img │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── react-logo.png │ │ ├── undraw_code_typing.svg │ │ ├── undraw_dev_productivity.svg │ │ └── undraw_online_party.svg └── yarn.lock ├── e2e └── nx-shopify-e2e │ ├── jest.config.js │ ├── tests │ └── nx-shopify.test.ts │ ├── tsconfig.json │ └── tsconfig.spec.json ├── jest.config.js ├── jest.preset.js ├── nx.json ├── package.json ├── packages └── nx-shopify │ ├── .eslintrc.json │ ├── README.md │ ├── executors.json │ ├── generators.json │ ├── jest.config.js │ ├── package.json │ ├── src │ ├── executors │ │ ├── build │ │ │ ├── build.executor.ts │ │ │ ├── ng-compat.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── deploy │ │ │ ├── deploy.executor.ts │ │ │ ├── ng-compat.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ └── serve │ │ │ ├── local-assets-server │ │ │ ├── assets-server-app.ts │ │ │ ├── index.ts │ │ │ ├── local-assets-server.ts │ │ │ └── shopify-sync │ │ │ │ └── shopify-sync-client.ts │ │ │ ├── local-development-server │ │ │ ├── index.ts │ │ │ ├── local-development-server.ts │ │ │ └── ssl │ │ │ │ ├── server-ssl.ts │ │ │ │ └── server.pem │ │ │ ├── ng-compat.ts │ │ │ ├── schema.d.ts │ │ │ ├── schema.json │ │ │ ├── serve.executor.spec.ts │ │ │ └── serve.executor.ts │ ├── generators │ │ ├── init │ │ │ ├── init.generator.spec.ts │ │ │ ├── init.generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── layout │ │ │ ├── files │ │ │ │ ├── __fileName__.layout.scss__template__ │ │ │ │ ├── __fileName__.layout.spec.ts__template__ │ │ │ │ ├── __fileName__.layout.ts__template__ │ │ │ │ └── __fileName__.liquid__template__ │ │ │ ├── layout.generator.spec.ts │ │ │ ├── layout.generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── section │ │ │ ├── files │ │ │ │ ├── __fileName__.liquid__template__ │ │ │ │ ├── __fileName__.section.scss__template__ │ │ │ │ ├── __fileName__.section.spec.ts__template__ │ │ │ │ └── __fileName__.section.ts__template__ │ │ │ ├── schema.d.ts │ │ │ ├── schema.json │ │ │ ├── section.generator.spec.ts │ │ │ └── section.generator.ts │ │ ├── snippet │ │ │ ├── files │ │ │ │ ├── __fileName__.liquid__template__ │ │ │ │ ├── __fileName__.snippet.scss__template__ │ │ │ │ ├── __fileName__.snippet.spec.ts__template__ │ │ │ │ └── __fileName__.snippet.ts__template__ │ │ │ ├── schema.d.ts │ │ │ ├── schema.json │ │ │ ├── snippet.generator.spec.ts │ │ │ └── snippet.generator.ts │ │ ├── template │ │ │ ├── files │ │ │ │ ├── __fileName__.liquid__template__ │ │ │ │ ├── __fileName__.template.scss__template__ │ │ │ │ ├── __fileName__.template.spec.ts__template__ │ │ │ │ └── __fileName__.template.ts__template__ │ │ │ ├── schema.d.ts │ │ │ ├── schema.json │ │ │ ├── template.generator.spec.ts │ │ │ └── template.generator.ts │ │ └── theme │ │ │ ├── files │ │ │ ├── README.md.template │ │ │ ├── __dot__eslintrc.json.template │ │ │ ├── __dot__gitignore.template │ │ │ ├── browserslist.template │ │ │ ├── config.example.yml.template │ │ │ ├── config.yml.template │ │ │ ├── package.json.template │ │ │ ├── postcss.config.js.template │ │ │ ├── proxy.conf.json.template │ │ │ ├── src │ │ │ │ ├── assets │ │ │ │ │ ├── favicon │ │ │ │ │ │ └── __dot__gitkeep.template │ │ │ │ │ ├── fonts │ │ │ │ │ │ └── __dot__gitkeep.template │ │ │ │ │ ├── images │ │ │ │ │ │ └── __dot__gitkeep.template │ │ │ │ │ └── svg │ │ │ │ │ │ ├── __dot__gitkeep.template │ │ │ │ │ │ └── example.svg.template │ │ │ │ ├── config │ │ │ │ │ ├── settings_data.json.template │ │ │ │ │ └── settings_schema.json.template │ │ │ │ ├── core │ │ │ │ │ ├── index.ts.template │ │ │ │ │ ├── life-cycle │ │ │ │ │ │ ├── index.ts.template │ │ │ │ │ │ └── theme-on-ready.ts.template │ │ │ │ │ ├── theme-bootstrap.spec.ts.template │ │ │ │ │ ├── theme-bootstrap.ts.template │ │ │ │ │ ├── theme-context.ts.template │ │ │ │ │ ├── theme-module.ts.template │ │ │ │ │ └── utils │ │ │ │ │ │ ├── index.ts.template │ │ │ │ │ │ └── theme-bootstrap-utils.ts.template │ │ │ │ ├── environments │ │ │ │ │ ├── environment-schema.ts.template │ │ │ │ │ ├── environment.prod.ts.template │ │ │ │ │ └── environment.ts.template │ │ │ │ ├── global │ │ │ │ │ ├── index.ts.template │ │ │ │ │ ├── theme-global-module.scss.template │ │ │ │ │ ├── theme-global-module.spec.ts.template │ │ │ │ │ └── theme-global-module.ts.template │ │ │ │ ├── locales │ │ │ │ │ └── en.default.json.template │ │ │ │ ├── main.ts.template │ │ │ │ ├── theme │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── index.ts.template │ │ │ │ │ │ ├── theme-layouts.ts.template │ │ │ │ │ │ └── theme │ │ │ │ │ │ │ ├── theme.layout.scss.template │ │ │ │ │ │ │ ├── theme.layout.spec.ts.template │ │ │ │ │ │ │ ├── theme.layout.ts.template │ │ │ │ │ │ │ └── theme.liquid.template │ │ │ │ │ ├── sections │ │ │ │ │ │ ├── footer │ │ │ │ │ │ │ ├── footer.liquid.template │ │ │ │ │ │ │ ├── footer.section.scss.template │ │ │ │ │ │ │ ├── footer.section.spec.ts.template │ │ │ │ │ │ │ └── footer.section.ts.template │ │ │ │ │ │ ├── header │ │ │ │ │ │ │ ├── header.liquid.template │ │ │ │ │ │ │ ├── header.section.scss.template │ │ │ │ │ │ │ ├── header.section.spec.ts.template │ │ │ │ │ │ │ └── header.section.ts.template │ │ │ │ │ │ └── index.ts.template │ │ │ │ │ ├── snippets │ │ │ │ │ │ ├── index.ts.template │ │ │ │ │ │ ├── message │ │ │ │ │ │ │ ├── message-body │ │ │ │ │ │ │ │ ├── message-body.liquid.template │ │ │ │ │ │ │ │ ├── message-body.scss.template │ │ │ │ │ │ │ │ ├── message-body.snippet.spec.ts.template │ │ │ │ │ │ │ │ └── message-body.snippet.ts.template │ │ │ │ │ │ │ ├── message.liquid.template │ │ │ │ │ │ │ ├── message.snippet.scss.template │ │ │ │ │ │ │ ├── message.snippet.spec.ts.template │ │ │ │ │ │ │ └── message.snippet.ts.template │ │ │ │ │ │ ├── product │ │ │ │ │ │ │ ├── product-gallery │ │ │ │ │ │ │ │ ├── product-gallery.liquid.template │ │ │ │ │ │ │ │ ├── product-gallery.snippet.scss.template │ │ │ │ │ │ │ │ ├── product-gallery.snippet.spec.ts.template │ │ │ │ │ │ │ │ └── product-gallery.snippet.ts.template │ │ │ │ │ │ │ └── product-recommendations │ │ │ │ │ │ │ │ ├── product-recommendations.liquid.template │ │ │ │ │ │ │ │ ├── product-recommendations.snippet.scss.template │ │ │ │ │ │ │ │ ├── product-recommendations.snippet.spec.ts.template │ │ │ │ │ │ │ │ └── product-recommendations.snippet.ts.template │ │ │ │ │ │ └── theme-context │ │ │ │ │ │ │ └── theme-context.liquid.template │ │ │ │ │ └── templates │ │ │ │ │ │ ├── 404 │ │ │ │ │ │ ├── 404.liquid.template │ │ │ │ │ │ ├── 404.template.scss.template │ │ │ │ │ │ ├── 404.template.spec.ts.template │ │ │ │ │ │ └── 404.template.ts.template │ │ │ │ │ │ ├── article │ │ │ │ │ │ ├── article.liquid.template │ │ │ │ │ │ ├── article.template.scss.template │ │ │ │ │ │ ├── article.template.spec.ts.template │ │ │ │ │ │ └── article.template.ts.template │ │ │ │ │ │ ├── blog │ │ │ │ │ │ ├── blog.liquid.template │ │ │ │ │ │ ├── blog.template.scss.template │ │ │ │ │ │ ├── blog.template.spec.ts.template │ │ │ │ │ │ └── blog.template.ts.template │ │ │ │ │ │ ├── cart │ │ │ │ │ │ ├── cart.liquid.template │ │ │ │ │ │ ├── cart.template.scss.template │ │ │ │ │ │ ├── cart.template.spec.ts.template │ │ │ │ │ │ └── cart.template.ts.template │ │ │ │ │ │ ├── collection-list │ │ │ │ │ │ ├── collection-list.liquid.template │ │ │ │ │ │ ├── collection-list.template.scss.template │ │ │ │ │ │ ├── collection-list.template.spec.ts.template │ │ │ │ │ │ └── collection-list.template.ts.template │ │ │ │ │ │ ├── collection │ │ │ │ │ │ ├── collection.liquid.template │ │ │ │ │ │ ├── collection.template.scss.template │ │ │ │ │ │ ├── collection.template.spec.ts.template │ │ │ │ │ │ └── collection.template.ts.template │ │ │ │ │ │ ├── customers │ │ │ │ │ │ ├── account │ │ │ │ │ │ │ ├── account.liquid.template │ │ │ │ │ │ │ ├── customers.account.template.scss.template │ │ │ │ │ │ │ ├── customers.account.template.spec.ts.template │ │ │ │ │ │ │ └── customers.account.template.ts.template │ │ │ │ │ │ ├── activate_account │ │ │ │ │ │ │ ├── activate_account.liquid.template │ │ │ │ │ │ │ ├── customers.activate_account.template.scss.template │ │ │ │ │ │ │ ├── customers.activate_account.template.ts.template │ │ │ │ │ │ │ └── customers.active_account.template.spec.ts.template │ │ │ │ │ │ ├── addresses │ │ │ │ │ │ │ ├── addresses.liquid.template │ │ │ │ │ │ │ ├── customers.addresses.template.scss.template │ │ │ │ │ │ │ ├── customers.addresses.template.spec.ts.template │ │ │ │ │ │ │ └── customers.addresses.template.ts.template │ │ │ │ │ │ ├── login │ │ │ │ │ │ │ ├── customers.login.template.scss.template │ │ │ │ │ │ │ ├── customers.login.template.spec.ts.template │ │ │ │ │ │ │ ├── customers.login.template.ts.template │ │ │ │ │ │ │ └── login.liquid.template │ │ │ │ │ │ ├── order │ │ │ │ │ │ │ ├── customers.order.template.scss.template │ │ │ │ │ │ │ ├── customers.order.template.spec.ts.template │ │ │ │ │ │ │ ├── customers.order.template.ts.template │ │ │ │ │ │ │ └── order.liquid.template │ │ │ │ │ │ ├── register │ │ │ │ │ │ │ ├── customers.register.template.scss.template │ │ │ │ │ │ │ ├── customers.register.template.spec.ts.template │ │ │ │ │ │ │ ├── customers.register.template.ts.template │ │ │ │ │ │ │ └── register.liquid.template │ │ │ │ │ │ └── reset_password │ │ │ │ │ │ │ ├── customers.reset_password.template.scss.template │ │ │ │ │ │ │ ├── customers.reset_password.template.spec.ts.template │ │ │ │ │ │ │ ├── customers.reset_password.template.ts.template │ │ │ │ │ │ │ └── reset_password.liquid.template │ │ │ │ │ │ ├── gift_card │ │ │ │ │ │ ├── gift_card.liquid.template │ │ │ │ │ │ ├── gift_card.template.scss.template │ │ │ │ │ │ ├── gift_card.template.spec.ts.template │ │ │ │ │ │ └── gift_card.template.ts.template │ │ │ │ │ │ ├── index.ts.template │ │ │ │ │ │ ├── index │ │ │ │ │ │ ├── index.liquid.template │ │ │ │ │ │ ├── index.template.scss.template │ │ │ │ │ │ ├── index.template.spec.ts.template │ │ │ │ │ │ └── index.template.ts.template │ │ │ │ │ │ ├── list-collections │ │ │ │ │ │ ├── list-collections.liquid.template │ │ │ │ │ │ ├── list-collections.template.scss.template │ │ │ │ │ │ ├── list-collections.template.spec.ts.template │ │ │ │ │ │ └── list-collections.template.ts.template │ │ │ │ │ │ ├── page-contact │ │ │ │ │ │ ├── page-contact.liquid.template │ │ │ │ │ │ ├── page-contact.template.scss.template │ │ │ │ │ │ ├── page-contact.template.spec.ts.template │ │ │ │ │ │ └── page-contact.template.ts.template │ │ │ │ │ │ ├── page │ │ │ │ │ │ ├── page.liquid.template │ │ │ │ │ │ ├── page.template.scss.template │ │ │ │ │ │ ├── page.template.spec.ts.template │ │ │ │ │ │ └── page.template.ts.template │ │ │ │ │ │ ├── product │ │ │ │ │ │ ├── product.liquid.template │ │ │ │ │ │ ├── product.template.scss.template │ │ │ │ │ │ ├── product.template.spec.ts.template │ │ │ │ │ │ └── product.template.ts.template │ │ │ │ │ │ ├── search │ │ │ │ │ │ ├── search.liquid.template │ │ │ │ │ │ ├── search.template.scss.template │ │ │ │ │ │ ├── search.template.spec.ts.template │ │ │ │ │ │ └── search.template.ts.template │ │ │ │ │ │ └── theme-templates.ts.template │ │ │ │ └── typings.d.ts.template │ │ │ ├── tsconfig.app.json.template │ │ │ ├── tsconfig.json.template │ │ │ └── tsconfig.spec.json.template │ │ │ ├── lib │ │ │ └── add-jest.ts │ │ │ ├── schema.d.ts │ │ │ ├── schema.json │ │ │ ├── theme.generator.spec.ts │ │ │ └── theme.generator.ts │ ├── index.ts │ ├── utils │ │ ├── config-utils.ts │ │ ├── generator-utils.ts │ │ ├── local-server │ │ │ └── network-utils.ts │ │ ├── normalize-utils.ts │ │ ├── output-dir-utils.ts │ │ ├── shopify │ │ │ ├── index.ts │ │ │ ├── shopify-api-models.ts │ │ │ ├── shopify-api-utils.ts │ │ │ └── shopify-theme-utils.ts │ │ ├── themekit │ │ │ ├── index.ts │ │ │ ├── themekit-cli-utils.ts │ │ │ ├── themekit-config-utils.ts │ │ │ └── themekit-validation-utils.ts │ │ ├── versions.ts │ │ ├── webpack-utils.ts │ │ └── workspace-utils.ts │ └── webpack │ │ ├── configs │ │ ├── hmr │ │ │ ├── hmr-alamo-loader.ts │ │ │ └── hot-client.js │ │ ├── partials │ │ │ ├── core.config.ts │ │ │ └── styles.config.ts │ │ ├── shopify.config.ts │ │ └── templates │ │ │ ├── script-tags.html │ │ │ ├── style-tags.html │ │ │ └── webpack-public-path.html │ │ └── utils │ │ ├── hmr │ │ └── hot-update-utils.ts │ │ ├── index.ts │ │ └── output-utils.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── release.config.js ├── tools ├── generators │ └── .gitkeep ├── scripts │ ├── commit-lint.js │ ├── rebuild.sh │ ├── release-env.example.sh │ └── replace-themekit.sh └── tsconfig.tools.json ├── tsconfig.base.json ├── workspace.json └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "nx-shopify", 3 | "projectOwner": "trafilea", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "packages/nx-shopify/README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "angular", 12 | "contributors": [ 13 | { 14 | "login": "sebastiandg7", 15 | "name": "Sebastian Duque Gutierrez", 16 | "avatar_url": "https://avatars0.githubusercontent.com/u/13395979?v=4", 17 | "profile": "https://sebastiandg7.github.io/", 18 | "contributions": [ 19 | "code", 20 | "infra", 21 | "ideas", 22 | "blog", 23 | "doc" 24 | ] 25 | }, 26 | { 27 | "login": "karensantana", 28 | "name": "Karen Santana", 29 | "avatar_url": "https://avatars1.githubusercontent.com/u/2827260?v=4", 30 | "profile": "https://www.karensantana.co/", 31 | "contributions": [ 32 | "code", 33 | "ideas" 34 | ] 35 | }, 36 | { 37 | "login": "andisadiazl", 38 | "name": "Andisa Diaz", 39 | "avatar_url": "https://avatars1.githubusercontent.com/u/31493497?v=4", 40 | "profile": "https://github.com/andisadiazl", 41 | "contributions": [ 42 | "code" 43 | ] 44 | }, 45 | { 46 | "login": "mvuljevas", 47 | "name": "Mauricio Vuljevas", 48 | "avatar_url": "https://avatars1.githubusercontent.com/u/14046897?v=4", 49 | "profile": "https://www.mvuljevas.com/", 50 | "contributions": [ 51 | "ideas" 52 | ] 53 | }, 54 | { 55 | "login": "jsalinasvela", 56 | "name": "Jesus Salinas Vela", 57 | "avatar_url": "https://avatars2.githubusercontent.com/u/28662284?v=4", 58 | "profile": "https://github.com/jsalinasvela", 59 | "contributions": [ 60 | "ideas", 61 | "projectManagement" 62 | ] 63 | }, 64 | { 65 | "login": "sophiecarreras", 66 | "name": "Sophie", 67 | "avatar_url": "https://avatars0.githubusercontent.com/u/49928680?v=4", 68 | "profile": "https://github.com/sophiecarreras", 69 | "contributions": [ 70 | "projectManagement" 71 | ] 72 | }, 73 | { 74 | "login": "jibinycricket", 75 | "name": "Jibin Mathew", 76 | "avatar_url": "https://avatars.githubusercontent.com/u/11200396?v=4", 77 | "profile": "https://github.com/jibinycricket", 78 | "contributions": [ 79 | "code", 80 | "bug" 81 | ] 82 | } 83 | ], 84 | "contributorsPerLine": 7 85 | } 86 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nrwl/nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nrwl/nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '🐞 Bug Report' 3 | about: Report Current Behavior that is believed to be unintentional or unexpected. 4 | labels: 'bug' 5 | --- 6 | 7 | 8 | 9 | ## Current Behavior 10 | 11 | 12 | 13 | ## Expected Behavior 14 | 15 | 16 | 17 | 18 | ## Steps to Reproduce 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | This issue may not be prioritized if details are not provided to help us reproduce the issue. 30 | 31 | ### Failure Logs 32 | 33 | 34 | 35 | ### Environment 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: Request Behavior that does not currently exist in nx-shopify 4 | labels: 'feature' 5 | --- 6 | 7 | 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Motivation 14 | 15 | 16 | 17 | ## Suggested Implementation 18 | 19 | 20 | 21 | ## Alternate Implementations 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '💡 Discussion' 3 | about: 'Start a thread to discuss an idea' 4 | labels: 'question / discussion' 5 | --- 6 | 7 | 8 | 9 | ## Description 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Read the Community Guidelines 4 | about: "Please make sure you have read the submission guidelines before posting an issue" 5 | url: https://github.com/trafilea/nx-shopify/blob/master/CONTRIBUTING.md#-submitting-an-issue 6 | - name: Is you issue Nx related? 7 | about: "If you issue is not related with this plugin but rather related with Nx itself, please go to the Nx project and report it there." 8 | url: https://github.com/nrwl/nx 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ## Current Behavior 8 | 9 | 10 | 11 | ## Expected Behavior 12 | 13 | 14 | 15 | ## Related Issue(s) 16 | 17 | 18 | 19 | Fixes # 20 | -------------------------------------------------------------------------------- /.github/workflows/e2e.yml: -------------------------------------------------------------------------------- 1 | name: e2e 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | run_e2e: 11 | name: Run e2e 12 | runs-on: ubuntu-latest 13 | env: 14 | NX_BRANCH: ${{ github.event.number }} 15 | NX_RUN_GROUP: ${{ github.run_id }} 16 | NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }} 17 | strategy: 18 | matrix: 19 | node-version: [12.x, 14.x] 20 | steps: 21 | - name: Checkout Repo 22 | uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - name: Install dependencies and run test 28 | run: | 29 | yarn 30 | yarn e2e nx-shopify-e2e -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | # Nx-Shopify 42 | /tools/scripts/release-env.sh 43 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | CHANGELOG.md 6 | /packages/nx-shopify/src/webpack/configs/templates/script-tags.html 7 | /packages/nx-shopify/src/webpack/configs/templates/style-tags.html 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode.vscode-typescript-tslint-plugin", 4 | "esbenp.prettier-vscode", 5 | "firsttris.vscode-jest-runner" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2021 Trafilea. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | packages/nx-shopify/README.md -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```console 8 | yarn install 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```console 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```console 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ## Deployment 28 | 29 | ```console 30 | GIT_USER= USE_SSH=true yarn deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/docs/cli-usage/executors/deploy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploy Command 3 | --- 4 | 5 | Builds a theme using the specified build target configuration and deploys it to a Shopify theme configured in the thems's `./config.yml` file (`'development'` by default). 6 | 7 | ## Usage 8 | 9 | ```bash 10 | $ nx deploy [options,...] 11 | ``` 12 | 13 | ## Configuration 14 | 15 | The `deploy` command is configured as a project target in the `workspace.json` file at your workspace root. By default, the target configuration should look similar to this: 16 | 17 | ```json 18 | { 19 | "projects": { 20 | "my-theme": { 21 | "targets": { 22 | "deploy": { 23 | "executor": "@trafilea/nx-shopify:deploy", 24 | "options": { 25 | "buildTarget": "my-theme:build" 26 | }, 27 | "configurations": { 28 | "production": { 29 | "buildTarget": "my-theme:build:production", 30 | "themekitEnv": "production" 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | The deploy target comes with a default `production` configuration that can be executed with: 41 | 42 | ```bash 43 | nx deploy --configuration=production 44 | nx deploy --c=production # same 45 | nx deploy --prod # same, only works for the 'production' named config 46 | ``` 47 | 48 | You can add additional configurations that define new options or override the ones defined in the default options object. 49 | 50 | :::tip 51 | 52 | Learn more about Nx targets configurations at the [Nx website](https://nx.dev) 53 | 54 | ::: 55 | 56 | You can also override/define options passing them as CLI arguments, these will take precedence over the `workspace.json` configurations. 57 | 58 | Example: 59 | 60 | ```bash 61 | nx serve --prod --themekitEnv staging --allowLive 62 | ``` 63 | 64 | ## Options 65 | 66 | ### --buildTarget 67 | 68 | Type: `string` 69 | 70 | Name of the target to be used in the theme build process. 71 | 72 | ### --themekitEnv 73 | 74 | Type: `string` 75 | 76 | Name of the themekit config.yml environment to be used in the deployment ('development' by default) (default: development) 77 | 78 | ### --allowLive 79 | 80 | Type: `boolean` 81 | 82 | Enables making changes to the Shopify Live Theme 83 | 84 | ### --open 85 | 86 | Type: `boolean` 87 | 88 | Open theme preview in the broswer when the deployment is done. 89 | -------------------------------------------------------------------------------- /docs/docs/cli-usage/executors/test.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test Command 3 | --- 4 | 5 | Run unit tests inside a theme 6 | 7 | ## Usage 8 | 9 | ```bash 10 | $ nx test [options,...] 11 | ``` 12 | 13 | ## Configuration 14 | 15 | The `test` command is configured as a project target in the `workspace.json` file at your workspace root. This target is handled by the `@nrwl/jest` plugin, read more about it at the [official docs](https://nx.dev/latest/angular/jest/overview). 16 | 17 | -------------------------------------------------------------------------------- /docs/docs/cli-usage/generators/layout.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Layout Generator 3 | --- 4 | 5 | Create a theme layout 6 | 7 | ## Usage 8 | 9 | ```bash 10 | $ nx generate layout [options,...] 11 | ``` 12 | 13 | ```bash 14 | $ nx g l [options,...] # same 15 | ``` 16 | 17 | By default, Nx will search for the `layout` generator in the default collection provisioned in `workspace.json`. 18 | 19 | You can specify the collection explicitly as follows: 20 | 21 | ```bash 22 | $ nx g @trafilea/nx-shopify:layout [options,...] 23 | ``` 24 | 25 | Show what will be generated without writing to disk: 26 | 27 | ```bash 28 | $ nx g layout [options,...] --dry-run 29 | ``` 30 | 31 | ### Examples 32 | 33 | Generate a layout in the my-theme theme: 34 | 35 | ```bash 36 | $ nx g layout my-layout --project=my-theme 37 | ``` 38 | 39 | This creates the following files: 40 | 41 | ```diff 42 | apps 43 | └── my-theme 44 | └── src 45 |    └── theme 46 |       ├── layout 47 | +       |   └── my-layout 48 | +       |      ├── my-layout.layout.scss 49 | +       |      ├── my-layout.layout.ts 50 | +       |      └── my-layout.liquid 51 |       ├── sections 52 |       ├── snippets 53 |       └── templates 54 | ``` 55 | 56 | Then you should add the generated layout to the `apps/my-theme/src/theme/layout/theme-layouts.ts` exported `themeLayouts` object so the new layout is loaded in the bootstrap process: 57 | 58 | ```diff title="theme-layouts.ts" 59 | export const themeLayouts = { 60 | theme: () => import('./theme/theme.layout').then((m) => m.ThemeLayout), 61 | + 'my-layout': () => import('./my-layout/my-layout.layout').then((m) => m.MyLayoutLayout), 62 | }; 63 | ``` 64 | 65 | :::tip 66 | 67 | If want to know more about how the `theme-layouts.ts` file works, head to the [Theme Boostrap Process](../../fundamentals/theme-bootstrap) doc 68 | 69 | ::: 70 | 71 | ## Options 72 | 73 | ### --name 74 | 75 | Type: `string` 76 | 77 | The name of the layout. 78 | 79 | ### --project 80 | 81 | Alias(es): p 82 | 83 | Type: `string` 84 | 85 | The name of the project where the layout will be generated. 86 | 87 | ### --directory 88 | 89 | Alias(es): d 90 | 91 | Type: `string` 92 | 93 | Create the layout under this directory relative to src/theme/layout (can be nested). 94 | 95 | ### --flat 96 | 97 | Default: `false` 98 | 99 | Type: `boolean` 100 | 101 | Create layout files at the directory root rather than its own directory. 102 | 103 | ### --liquidOnly 104 | 105 | Default: `false` 106 | 107 | Type: `boolean` 108 | 109 | When true, does not create files other than the liquid file for the new layout. 110 | 111 | ### --skipTests 112 | 113 | Default: `false` 114 | 115 | Type: `boolean` 116 | 117 | When true, does not create \"spec.ts\" test files for the new layout. 118 | -------------------------------------------------------------------------------- /docs/docs/cli-usage/generators/section.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Section Generator 3 | --- 4 | 5 | Create a theme section 6 | 7 | ## Usage 8 | 9 | ```bash 10 | $ nx generate section [options,...] 11 | ``` 12 | 13 | ```bash 14 | $ nx g sec [options,...] # same 15 | ``` 16 | 17 | By default, Nx will search for the `section` generator in the default collection provisioned in `workspace.json`. 18 | 19 | You can specify the collection explicitly as follows: 20 | 21 | ```bash 22 | $ nx g @trafilea/nx-shopify:section [options,...] 23 | ``` 24 | 25 | Show what will be generated without writing to disk: 26 | 27 | ```bash 28 | $ nx g section [options,...] --dry-run 29 | ``` 30 | 31 | ### Examples 32 | 33 | Generate a section in the my-theme theme: 34 | 35 | ```bash 36 | $ nx g section my-section --project=my-theme 37 | ``` 38 | 39 | This creates the following files: 40 | 41 | ```diff 42 | apps 43 | └── my-theme 44 | └── src 45 |    └── theme 46 |       ├── layout 47 |       ├── sections 48 | +       |   └── my-section 49 | +       |      ├── my-section.section.scss 50 | +       |      ├── my-section.section.ts 51 | +       |      └── my-section.liquid 52 |       ├── snippets 53 |       └── templates 54 | ``` 55 | 56 | The `my-section.section.ts` file exports a `MySectionSection` class that now you can import in any other theme block (layout, template, snippet or other section). 57 | 58 | ## Options 59 | 60 | ### --name 61 | 62 | Type: `string` 63 | 64 | The name of the section. 65 | 66 | ### --project 67 | 68 | Alias(es): p 69 | 70 | Type: `string` 71 | 72 | The name of the project where the section will be generated. 73 | 74 | ### --directory 75 | 76 | Alias(es): d 77 | 78 | Type: `string` 79 | 80 | Create the section under this directory relative to src/theme/sections (can be nested). 81 | 82 | ### --flat 83 | 84 | Default: `false` 85 | 86 | Type: `boolean` 87 | 88 | Create section files at the directory root rather than its own directory. 89 | 90 | ### --liquidOnly 91 | 92 | Default: `false` 93 | 94 | Type: `boolean` 95 | 96 | When true, does not create files other than the liquid file for the new section. 97 | 98 | ### --skipTests 99 | 100 | Default: `false` 101 | 102 | Type: `boolean` 103 | 104 | When true, does not create \"spec.ts\" test files for the new section. 105 | -------------------------------------------------------------------------------- /docs/docs/cli-usage/generators/snippet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Snippet Generator 3 | --- 4 | 5 | Create a theme snippet 6 | 7 | ## Usage 8 | 9 | ```bash 10 | $ nx generate snippet [options,...] 11 | ``` 12 | 13 | ```bash 14 | $ nx g snip [options,...] # same 15 | ``` 16 | 17 | By default, Nx will search for the `snippet` generator in the default collection provisioned in `workspace.json`. 18 | 19 | You can specify the collection explicitly as follows: 20 | 21 | ```bash 22 | $ nx g @trafilea/nx-shopify:snippet [options,...] 23 | ``` 24 | 25 | Show what will be generated without writing to disk: 26 | 27 | ```bash 28 | $ nx g snippet [options,...] --dry-run 29 | ``` 30 | 31 | ### Examples 32 | 33 | Generate a snippet in the my-theme theme: 34 | 35 | ```bash 36 | $ nx g snippet my-snippet --project=my-theme 37 | ``` 38 | 39 | This creates the following files: 40 | 41 | ```diff 42 | apps 43 | └── my-theme 44 | └── src 45 |    └── theme 46 |       ├── layout 47 |       ├── sections 48 |       ├── snippets 49 | +       |   └── my-snippet 50 | +       |      ├── my-snippet.snippet.scss 51 | +       |      ├── my-snippet.snippet.ts 52 | +       |      └── my-snippet.liquid 53 |       └── templates 54 | ``` 55 | 56 | The `my-snippet.snippet.ts` file exports a `MySnippetSnippet` class that now you can import in any other theme block (layout, template, section or other snippet). 57 | 58 | ## Options 59 | 60 | ### --name 61 | 62 | Type: `string` 63 | 64 | The name of the snippet. 65 | 66 | ### --project 67 | 68 | Alias(es): p 69 | 70 | Type: `string` 71 | 72 | The name of the project where the snippet will be generated. 73 | 74 | ### --directory 75 | 76 | Alias(es): d 77 | 78 | Type: `string` 79 | 80 | Create the snippet under this directory relative to src/theme/snippets (can be nested). 81 | 82 | ### --flat 83 | 84 | Default: `false` 85 | 86 | Type: `boolean` 87 | 88 | Create snippet files at the directory root rather than its own directory. 89 | 90 | ### --liquidOnly 91 | 92 | Default: `false` 93 | 94 | Type: `boolean` 95 | 96 | When true, does not create files other than the liquid file for the new snippet. 97 | 98 | ### --skipTests 99 | 100 | Default: `false` 101 | 102 | Type: `boolean` 103 | 104 | When true, does not create \"spec.ts\" test files for the new snippet. 105 | -------------------------------------------------------------------------------- /docs/docs/guides/extend-webpack.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Extend Webpack Configuration 3 | --- 4 | 5 | With extensibility in mind, the [Build Command](../cli-usage/executors/build) accepts a `--webpackConfig` option containing a path to a function which takes a webpack config, context and returns the resulting webpack config 6 | 7 | Here you have an example of a file containing such a function: 8 | 9 | ```javascript title="apps/my-theme/webpack.custom.js" 10 | const { merge } = require('webpack-merge'); 11 | 12 | module.exports = function (nxShopifyConfig, { options, configuration }) { 13 | const myConfig = { 14 | plugins: [new NewWebpackPlugin()], 15 | }; 16 | 17 | return merge(nxShopifyConfig, myConfig); 18 | }; 19 | ``` 20 | 21 | Then you would need to configure the `webpackConfig` option with the `"apps/my-theme/webpack.custom.js"` value. 22 | -------------------------------------------------------------------------------- /docs/docs/guides/liquid-in-styles.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Liquid in Styles 3 | --- 4 | 5 | Shopify has [deprected the use of SaSS in themes](https://www.shopify.com/partners/blog/deprecating-sass). But there are still ways of using Liquid to change the way your styles behave. Here is one simple approach to achieve this: 6 | 7 | ## Create a css-variables snippet 8 | 9 | Create a snippet in `src/theme/snippets/css-variables/css-variables.liquid` where you are going to define all the CSS variables that will be controled by liquid statements (generally settings). 10 | 11 | ```html title="css-variables.liquid" 12 | 18 | ``` 19 | 20 | Then, render this snippet in the head tag of your layout(s) before the `script-tags` render. 21 | 22 | ```html {5} title="src/theme/layout/theme/theme.liquid" 23 | 24 | 25 | 26 | ... {% render 'css-variables' %} {% render 'script-tags'%} ... 27 | 28 | 29 | ... 30 | 31 | 32 | ``` 33 | 34 | ## Initialize your Styles variables 35 | 36 | Now, in your style files you can make use of this CSS variables as you need. For example, you can create SASS variables with the CSS variables as their value: 37 | 38 | ```scss title="src/theme/layout/theme/theme.layout.scss" 39 | $color-primary: var(--color-primary); 40 | $color-secondary: var(--color-primary); 41 | 42 | .my_class { 43 | color: $color-primary; 44 | background-color: $color-secondary; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/docs/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | --- 4 | 5 | ## Prerequisites 6 | 7 | You will need to have an Nx workspace created to make use of this tool 8 | 9 | :::note 10 | 11 | Using Node 12+ and Nx 11+ is recommended 12 | 13 | ::: 14 | 15 | Install the Nx CLI globally 16 | 17 | ```bash 18 | # npm 19 | $ npm install --global nx 20 | 21 | # yarn 22 | $ yarn add --global nx 23 | 24 | # pnpm 25 | $ pnpm install --global nx 26 | ``` 27 | 28 | Create an empty Nx workspace (or use an existing one) 29 | 30 | ```bash 31 | $ npx create-nx-workspace --preset=empty 32 | $ cd ./ 33 | ``` 34 | 35 | Example: 36 | 37 | ```bash 38 | $ npx create-nx-workspace my-org --preset=empty 39 | $ cd ./my-org 40 | ``` 41 | 42 | --- 43 | 44 | ## Installing the plugin 45 | 46 | While in your Nx workspace, install the Nx-Shopify plugin as a devDependency 47 | 48 | ```bash 49 | # npm 50 | $ npm install --save-dev @trafilea/nx-shopify 51 | 52 | # yarn 53 | $ yarn add --save-dev @trafilea/nx-shopify 54 | 55 | # pnpm 56 | $ pnpm install --save-dev @trafilea/nx-shopify 57 | ``` 58 | 59 | Check the plugin was successfully installed by using the `nx list` command: 60 | 61 | ```bash 62 | $ nx list @trafilea/nx-shopify 63 | 64 | > NX Capabilities in @trafilea/nx-shopify: 65 | 66 | GENERATORS 67 | 68 | init : Initialize plugin 69 | theme : Generate a new Shopify theme 70 | layout : Generate a theme layout 71 | template : Generate a theme template 72 | snippet : Generate a theme snippet 73 | section : Generate a theme section 74 | 75 | EXECUTORS/BUILDERS 76 | 77 | build : Build a Shopify theme 78 | serve : Serves a Shopify theme for local development 79 | deploy : Deploy a Shopify theme to Shopify 80 | ``` 81 | 82 | Now you are ready to power-up your Shopify theme development experience! 83 | -------------------------------------------------------------------------------- /docs/docs/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | slug: / 4 | --- 5 | 6 |

7 | 8 | 9 | 10 |

11 |

12 | Nx-Shopify 13 |

14 | 15 | > 🔎 **A [Nx](https://nx.dev) plugin for developing performance-first Shopify themes 🚀** 16 | 17 | Be it you need to build a custom Shopify store theme, develop a generic theme or even maintain multiple stores/themes with shared code across them, this Nx plugin helps you power-up your development experience 18 | 19 |
20 | 21 |
22 | 23 | [![e2e](https://github.com/trafilea/nx-shopify/actions/workflows/e2e.yml/badge.svg)](https://github.com/trafilea/nx-shopify/actions/workflows/e2e.yml) 24 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 25 | [![License](https://img.shields.io/github/license/trafilea/nx-shopify)](https://github.com/trafilea/nx-shopify/blob/master/LICENSE) 26 | ![npm (scoped)](https://img.shields.io/npm/v/@trafilea/nx-shopify) 27 | ![npm](https://img.shields.io/npm/dt/@trafilea/nx-shopify) 28 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 29 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) 30 | 31 |
32 | 33 | This Nx Plugin for Shopify contains generators and executors for managing Shopify themes within an Nx workspace. It provides: 34 | 35 | - Support for writing themes using [TypeScript](https://www.typescriptlang.org/). 36 | - Out of the box code formatting using Prettier and ESLint. 37 | - Scaffolding for creating new themes with separate configs. 38 | - Scaffolding for creating theme block suchs as layouts, templates, sections and snippets. 39 | - Utilities for working with different application environments & [themekit](https://shopify.dev/tools/theme-kit) environments. 40 | 41 | [//]: # '- Integration with libraries such as [Jest](https://jestjs.io/) and Cypress.' 42 | 43 | # Get stared 44 | 45 | You can quickly jump in with the following commands: 46 | 47 | ```bash 48 | $ npx create-nx-workspace my-org --preset=empty 49 | $ cd ./my-org 50 | $ npm i -D @trafilea/nx-shopify 51 | $ nx g @trafilea/nx-shopify:theme my-theme 52 | # Configure your apps/my-theme/config.yml file 53 | $ nx serve my-theme 54 | $ nx build my-theme 55 | $ nx deploy my-theme 56 | ``` 57 | 58 | Read more about everything that comes with Nx-Shopify in our documentation. 59 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nx-shopify-docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "serve": "docusaurus serve", 12 | "clear": "docusaurus clear" 13 | }, 14 | "dependencies": { 15 | "@docusaurus/core": "2.0.0-alpha.72", 16 | "@docusaurus/preset-classic": "2.0.0-alpha.72", 17 | "@mdx-js/react": "^1.6.21", 18 | "clsx": "^1.1.1", 19 | "react": "^16.8.4", 20 | "react-dom": "^16.8.4", 21 | "react-helmet": "^6.1.0" 22 | }, 23 | "browserslist": { 24 | "production": [ 25 | ">0.5%", 26 | "not dead", 27 | "not op_mini all" 28 | ], 29 | "development": [ 30 | "last 1 chrome version", 31 | "last 1 firefox version", 32 | "last 1 safari version" 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | docs: [ 3 | { 4 | type: 'doc', 5 | id: 'introduction', 6 | }, 7 | { 8 | type: 'doc', 9 | id: 'installation', 10 | }, 11 | { 12 | type: 'category', 13 | label: 'Fundamentals', 14 | items: [ 15 | 'fundamentals/creating-a-theme', 16 | 'fundamentals/theme-structure', 17 | 'fundamentals/theme-bootstrap', 18 | ], 19 | }, 20 | { 21 | type: 'category', 22 | label: 'CLI Usage', 23 | items: [ 24 | { 25 | type: 'category', 26 | label: 'Code Generators', 27 | items: [ 28 | 'cli-usage/generators/layout', 29 | 'cli-usage/generators/template', 30 | 'cli-usage/generators/section', 31 | 'cli-usage/generators/snippet', 32 | ], 33 | }, 34 | { 35 | type: 'category', 36 | label: 'Theme Commands', 37 | items: [ 38 | 'cli-usage/executors/build', 39 | 'cli-usage/executors/serve', 40 | 'cli-usage/executors/test', 41 | 'cli-usage/executors/deploy', 42 | ], 43 | }, 44 | ], 45 | }, 46 | { 47 | type: 'category', 48 | label: 'Guides', 49 | items: [ 50 | 'guides/environments', 51 | 'guides/liquid-to-ts-context', 52 | 'guides/liquid-in-styles', 53 | 'guides/using-react', 54 | 'guides/extend-webpack', 55 | ], 56 | }, 57 | { 58 | type: 'category', 59 | label: 'Contributing', 60 | items: [ 61 | { 62 | type: 'link', 63 | label: 'Submit an issue', 64 | href: 'https://github.com/trafilea/nx-shopify/issues/new/choose', 65 | }, 66 | ], 67 | }, 68 | ], 69 | }; 70 | -------------------------------------------------------------------------------- /docs/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 4rem; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: left; 25 | } 26 | 27 | .features { 28 | display: flex; 29 | align-items: center; 30 | padding: 2rem 0; 31 | width: 100%; 32 | } 33 | 34 | .featureImage { 35 | height: 200px; 36 | width: 200px; 37 | } 38 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 16 | 22 | 24 | 29 | 32 | 34 | 39 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/static/img/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/docs/static/img/react-logo.png -------------------------------------------------------------------------------- /e2e/nx-shopify-e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'nx-shopify-e2e', 3 | preset: '../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]s$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'js', 'html'], 13 | coverageDirectory: '../../coverage/e2e/nx-shopify-e2e', 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/nx-shopify-e2e/tests/nx-shopify.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | checkFilesExist, 3 | ensureNxProject, 4 | readJson, 5 | runNxCommandAsync, 6 | uniq, 7 | } from '@nrwl/nx-plugin/testing'; 8 | describe('nx-shopify e2e', () => { 9 | beforeAll(() => { 10 | ensureNxProject('@trafilea/nx-shopify', 'dist/packages/nx-shopify'); 11 | }); 12 | 13 | it('should create a theme', async (done) => { 14 | const plugin = uniq('nx-shopify'); 15 | await runNxCommandAsync(`generate @trafilea/nx-shopify:theme ${plugin}`); 16 | const result = await runNxCommandAsync(`build ${plugin}`); 17 | expect(result.stdout).toContain('Successfully built'); 18 | 19 | done(); 20 | }, 250000); 21 | 22 | describe('--directory', () => { 23 | it('should create src in the specified directory', async (done) => { 24 | const plugin = uniq('nx-shopify'); 25 | await runNxCommandAsync( 26 | `generate @trafilea/nx-shopify:theme ${plugin} --directory subdir` 27 | ); 28 | expect(() => 29 | checkFilesExist(`apps/subdir/${plugin}/config.yml`) 30 | ).not.toThrow(); 31 | done(); 32 | }, 120000); 33 | }); 34 | 35 | describe('--tags', () => { 36 | it('should add tags to nx.json', async (done) => { 37 | const plugin = uniq('nx-shopify'); 38 | await runNxCommandAsync( 39 | `generate @trafilea/nx-shopify:theme ${plugin} --tags e2etag,e2ePackage` 40 | ); 41 | const nxJson = readJson('nx.json'); 42 | expect(nxJson.projects[plugin].tags).toEqual(['e2etag', 'e2ePackage']); 43 | done(); 44 | }, 120000); 45 | }); 46 | 47 | it('should pass unit tests', async (done) => { 48 | const themeName = uniq('nx-shopify'); 49 | await runNxCommandAsync(`generate @trafilea/nx-shopify:theme ${themeName}`); 50 | const result = runNxCommandAsync(`test ${themeName}`); 51 | await expect(result).resolves.toBeTruthy(); 52 | done(); 53 | }, 250000); 54 | }); 55 | -------------------------------------------------------------------------------- /e2e/nx-shopify-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.e2e.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /e2e/nx-shopify-e2e/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projects: ['/packages/nx-shopify', '/e2e/nx-shopify-e2e'], 3 | }; 4 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset'); 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "trafilea", 3 | "affected": { 4 | "defaultBase": "master" 5 | }, 6 | "implicitDependencies": { 7 | "workspace.json": "*", 8 | "package.json": { 9 | "dependencies": "*", 10 | "devDependencies": "*" 11 | }, 12 | "tsconfig.base.json": "*", 13 | "tslint.json": "*", 14 | ".eslintrc.json": "*", 15 | "nx.json": "*" 16 | }, 17 | "tasksRunnerOptions": { 18 | "default": { 19 | "runner": "@nrwl/nx-cloud", 20 | "options": { 21 | "cacheableOperations": ["build", "lint", "test", "e2e"], 22 | "accessToken": "ZTc0ZDBjM2YtNWVkZS00ZTMwLWFhZWQtM2RiZGFlMzlmNjM0fHJlYWQ=", 23 | "canTrackAnalytics": true, 24 | "showUsageWarnings": true 25 | } 26 | } 27 | }, 28 | "projects": { 29 | "nx-shopify": { 30 | "tags": [] 31 | }, 32 | "nx-shopify-e2e": { 33 | "tags": [], 34 | "implicitDependencies": ["nx-shopify"] 35 | }, 36 | "nx-shopify-docs": { 37 | "tags": [] 38 | } 39 | }, 40 | "workspaceLayout": { 41 | "appsDir": "e2e", 42 | "libsDir": "packages" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/nx-shopify/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "rules": {}, 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "parserOptions": { 9 | "project": ["packages/nx-shopify/tsconfig.*?.json"] 10 | }, 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.ts", "*.tsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.js", "*.jsx"], 19 | "rules": {} 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/nx-shopify/executors.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "executors": { 4 | "build": { 5 | "implementation": "./src/executors/build/build.executor", 6 | "schema": "./src/executors/build/schema.json", 7 | "description": "Build a Shopify theme" 8 | }, 9 | "serve": { 10 | "implementation": "./src/executors/serve/serve.executor", 11 | "schema": "./src/executors/serve/schema.json", 12 | "description": "Serves a Shopify theme for local development" 13 | }, 14 | "deploy": { 15 | "implementation": "./src/executors/deploy/deploy.executor", 16 | "schema": "./src/executors/deploy/schema.json", 17 | "description": "Deploy a Shopify theme to Shopify" 18 | } 19 | }, 20 | "builders": { 21 | "build": { 22 | "implementation": "./src/executors/build/ng-compat", 23 | "schema": "./src/executors/build/schema.json", 24 | "description": "Build a Shopify theme" 25 | }, 26 | "serve": { 27 | "implementation": "./src/executors/serve/ng-compat", 28 | "schema": "./src/executors/serve/schema.json", 29 | "description": "Serves a Shopify theme for local development" 30 | }, 31 | "deploy": { 32 | "implementation": "./src/executors/deploy/ng-compat", 33 | "schema": "./src/executors/deploy/schema.json", 34 | "description": "Deploy a Shopify theme to Shopify" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/nx-shopify/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'nx-shopify', 3 | preset: '../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]sx?$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 13 | coverageDirectory: '../../coverage/packages/nx-shopify', 14 | }; 15 | -------------------------------------------------------------------------------- /packages/nx-shopify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trafilea/nx-shopify", 3 | "version": "0.0.0-development", 4 | "description": "A Nx plugin for developing performance-first Shopify themes 🚀", 5 | "license": "MIT", 6 | "homepage": "https://trafilea.github.io/nx-shopify", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/trafilea/nx-shopify.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/trafilea/nx-shopify/issues" 13 | }, 14 | "keywords": [ 15 | "nx", 16 | "nrwl-nx", 17 | "nx-plugin", 18 | "nx-shopify", 19 | "trafilea", 20 | "ecommerce", 21 | "shopify", 22 | "themekit" 23 | ], 24 | "main": "src/index.js", 25 | "generators": "./generators.json", 26 | "executors": "./executors.json", 27 | "dependencies": { 28 | "css-loader": "^5.1.3", 29 | "file-loader": "^6.2.0", 30 | "fork-ts-checker-webpack-plugin": "^6.1.1", 31 | "identity-obj-proxy": "3.0.0", 32 | "postcss": "^8.2.8", 33 | "postcss-loader": "^4.1.0", 34 | "sass": "^1.32.8", 35 | "sass-loader": "^10.0.3", 36 | "style-loader": "^2.0.0", 37 | "ts-loader": "^8.0.18", 38 | "webpack-dev-server": "^3.11.2" 39 | }, 40 | "publishConfig": { 41 | "access": "public" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/build/build.executor.ts: -------------------------------------------------------------------------------- 1 | import { ExecutorContext, logger } from '@nrwl/devkit'; 2 | import { 3 | getEmittedFiles, 4 | runWebpack, 5 | } from '@nrwl/workspace/src/utilities/run-webpack'; 6 | import * as webpack from 'webpack'; 7 | import { from } from 'rxjs'; 8 | import { eachValueFrom } from 'rxjs-for-await'; 9 | import { concatMap, map, tap } from 'rxjs/operators'; 10 | import { normalizeBuildOptions } from '../../utils/normalize-utils'; 11 | import { deleteOutputDir } from '../../utils/output-dir-utils'; 12 | import { getSourceRoot } from '../../utils/workspace-utils'; 13 | import { getShopifyWebpackConfig } from '../../webpack/configs/shopify.config'; 14 | import { BuildExecutorSchema } from './schema'; 15 | 16 | export function buildExecutor( 17 | options: BuildExecutorSchema, 18 | context: ExecutorContext 19 | ) { 20 | const projectName = context.projectName; 21 | if (!projectName) { 22 | throw new Error('The builder requires a target.'); 23 | } 24 | 25 | // Delete output path before bundling 26 | deleteOutputDir(context.root, options.outputPath); 27 | 28 | return eachValueFrom( 29 | from(getSourceRoot(context)).pipe( 30 | map((sourceRoot) => 31 | normalizeBuildOptions(options, context.root, sourceRoot) 32 | ), 33 | concatMap((normalizedOptions) => { 34 | const webpackConfig = getShopifyWebpackConfig(normalizedOptions, false); 35 | return runWebpack(webpackConfig, webpack).pipe( 36 | tap((stats) => { 37 | logger.info(stats.toString(webpackConfig.stats)); 38 | }) 39 | ); 40 | }), 41 | map((webpackStats) => { 42 | return { 43 | success: webpackStats && !webpackStats.hasErrors(), 44 | emittedFiles: getEmittedFiles(webpackStats), 45 | }; 46 | }), 47 | tap((builderOutput) => { 48 | // context.logger.info(JSON.stringify(builderOutput.webpackStats['errors'])); 49 | if (builderOutput.success) { 50 | logger.info(`🎉 Successfully built ${projectName} theme\n`); 51 | } else { 52 | logger.error(`❌ Failed to build ${projectName} theme\n`); 53 | } 54 | }) 55 | ) 56 | ); 57 | } 58 | 59 | export default buildExecutor; 60 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/build/ng-compat.ts: -------------------------------------------------------------------------------- 1 | import { convertNxExecutor } from '@nrwl/devkit'; 2 | import { buildExecutor } from './build.executor'; 3 | 4 | export default convertNxExecutor(buildExecutor); 5 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface AssetObj { 2 | input: string; 3 | output: string; 4 | glob: string; 5 | ignore?: string; 6 | } 7 | 8 | export type SourceMapOptions = 'source-map' | 'inline-source-map'; 9 | 10 | export interface FileReplacement { 11 | replace: string; 12 | with: string; 13 | } 14 | 15 | export type Asset = string | AssetObj; 16 | export interface BuildExecutorSchema { 17 | outputPath: string; 18 | main: string; 19 | tsConfig: string; 20 | postcssConfig: string; 21 | themekitConfig: string; 22 | 23 | watch?: boolean; 24 | vendorChunk?: boolean; 25 | commonChunk?: boolean; 26 | runtimeChunk?: boolean; 27 | sourceMap?: boolean | SourceMapOptions; 28 | outputHashing?: string; 29 | optimization?: boolean | OptimizationOptions; 30 | showCircularDependencies?: boolean; 31 | memoryLimit?: number; 32 | poll?: number; 33 | 34 | fileReplacements?: FileReplacement[]; 35 | assets?: Array; 36 | 37 | progress?: boolean; 38 | analyze?: boolean; 39 | statsJson?: boolean; 40 | extractLicenses?: boolean; 41 | verbose?: boolean; 42 | 43 | webpackConfig?: string; 44 | 45 | root?: string; 46 | sourceRoot?: Path; 47 | } 48 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/deploy/deploy.executor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExecutorContext, 3 | logger, 4 | parseTargetString, 5 | readTargetOptions, 6 | runExecutor, 7 | } from '@nrwl/devkit'; 8 | import { BuildExecutorSchema } from '../../executors/build/schema'; 9 | import { runThemekitCommand } from '../../utils/themekit'; 10 | import { DeployExecutorSchema } from './schema'; 11 | 12 | export async function deployExecutor( 13 | options: DeployExecutorSchema, 14 | context: ExecutorContext 15 | ) { 16 | const projectName = context.projectName ?? 'your'; 17 | const { 18 | open, 19 | themekitEnv: env = 'development', 20 | allowLive = false, 21 | buildTarget, 22 | } = options; 23 | const buildOptions: BuildExecutorSchema = getBuildOptions(options, context); 24 | const { outputPath } = buildOptions; 25 | 26 | await runExecutor(parseTargetString(buildTarget), {}, context); 27 | 28 | for await (const output of await runExecutor<{ 29 | success: boolean; 30 | }>(parseTargetString(buildTarget), {}, context)) { 31 | if (!output.success) throw new Error('Could not compile application files'); 32 | } 33 | 34 | try { 35 | await runThemekitCommand('version'); 36 | await runThemekitCommand('deploy', { env, allowLive }, { cwd: outputPath }); 37 | 38 | if (open) { 39 | await runThemekitCommand('open', { env }, { cwd: outputPath }); 40 | } 41 | 42 | logger.info(`🎉 Successfully deployed ${projectName} theme to Shopify`); 43 | return { success: true }; 44 | } catch (error) { 45 | logger.error(`❌ Failed to deploy ${projectName} theme to Shopify`); 46 | logger.error(error); 47 | return { success: true }; 48 | } 49 | } 50 | 51 | function getBuildOptions( 52 | options: DeployExecutorSchema, 53 | context: ExecutorContext 54 | ): BuildExecutorSchema { 55 | const target = parseTargetString(options.buildTarget); 56 | const overrides: Partial = { 57 | watch: false, 58 | }; 59 | 60 | const buildOptions = readTargetOptions(target, context); 61 | 62 | return { 63 | ...buildOptions, 64 | ...overrides, 65 | }; 66 | } 67 | 68 | export default deployExecutor; 69 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/deploy/ng-compat.ts: -------------------------------------------------------------------------------- 1 | import { convertNxExecutor } from '@nrwl/devkit'; 2 | import { deployExecutor } from './deploy.executor'; 3 | 4 | export default convertNxExecutor(deployExecutor); 5 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/deploy/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface DeployExecutorSchema { 2 | buildTarget: string; 3 | themekitEnv: string; 4 | open: boolean; 5 | allowLive: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/deploy/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "title": "Shopify Theme Deploy Target", 5 | "description": "Shopify theme deploy target options", 6 | "type": "object", 7 | "properties": { 8 | "buildTarget": { 9 | "type": "string", 10 | "description": "Name of the target to be used in the theme build process." 11 | }, 12 | "themekitEnv": { 13 | "type": "string", 14 | "description": "Name of the themekit config.yml environment to be used in the deployment ('development' by default)", 15 | "default": "development" 16 | }, 17 | "allowLive": { 18 | "type": "boolean", 19 | "description": "Enables making changes to the Shopify Live Theme", 20 | "default": false 21 | }, 22 | "open": { 23 | "type": "boolean", 24 | "description": "Open theme preview in the broswer when the deployment is done.", 25 | "default": false, 26 | "alias": "o" 27 | } 28 | }, 29 | "additionalProperties": false, 30 | "required": ["buildTarget"] 31 | } 32 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/local-assets-server/assets-server-app.ts: -------------------------------------------------------------------------------- 1 | import * as corsMiddleware from 'cors'; 2 | import * as express from 'express'; 3 | import * as webpackDevMiddleware from 'webpack-dev-middleware'; 4 | import * as webpackHotMiddleware from 'webpack-hot-middleware'; 5 | import { isHotUpdateFile } from '../../../webpack/utils'; 6 | 7 | export class AssetsServerApp { 8 | webpackDevMiddleware; 9 | webpackHotMiddleware; 10 | 11 | constructor(compiler) { 12 | this.webpackDevMiddleware = webpackDevMiddleware(compiler, { 13 | writeToDisk: (filePath: string) => { 14 | return !isHotUpdateFile(filePath); 15 | }, 16 | }); 17 | 18 | this.webpackHotMiddleware = webpackHotMiddleware(compiler, { 19 | log: false, 20 | }); 21 | } 22 | 23 | buildServer() { 24 | const app = express(); 25 | app.use(corsMiddleware()); 26 | app.use(this.webpackDevMiddleware); 27 | app.use(this.webpackHotMiddleware); 28 | return app; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/local-assets-server/index.ts: -------------------------------------------------------------------------------- 1 | export * from './local-assets-server'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/local-assets-server/shopify-sync/shopify-sync-client.ts: -------------------------------------------------------------------------------- 1 | import { AsyncSeriesHook, SyncHook } from 'tapable'; 2 | import { Stats as WebpackStats } from 'webpack'; 3 | import { runThemekitCommand, ThemeKitFlags } from '../../../../utils/themekit'; 4 | 5 | export class ShopifySyncClient { 6 | skipNextSync: boolean; 7 | isDeploymentInProgress: boolean; 8 | filesPendingDeploy: string[]; 9 | 10 | hooks = { 11 | beforeSync: new AsyncSeriesHook<[string[], WebpackStats]>([ 12 | 'files', 13 | 'stats', 14 | ]), 15 | sync: new SyncHook<[string[], WebpackStats]>(['files', 'stats']), 16 | syncDone: new SyncHook<[string[], WebpackStats]>(['files', 'stats']), 17 | afterSync: new AsyncSeriesHook<[string[], WebpackStats]>([ 18 | 'files', 19 | 'stats', 20 | ]), 21 | syncSkipped: new SyncHook<[string[], WebpackStats]>(['files', 'stats']), 22 | }; 23 | 24 | constructor() { 25 | this.skipNextSync = false; 26 | this.isDeploymentInProgress = false; 27 | this.filesPendingDeploy = []; 28 | } 29 | 30 | async syncChangedFiles( 31 | changedFiles: string[], 32 | stats: WebpackStats, 33 | themekitFlags: ThemeKitFlags 34 | ) { 35 | if (this.isDeploymentInProgress) { 36 | this.filesPendingDeploy = [ 37 | ...new Set([...this.filesPendingDeploy, ...changedFiles]), 38 | ]; 39 | throw new Error('A deployment is already in progress'); 40 | } 41 | 42 | await this.hooks.beforeSync.promise(changedFiles, stats); 43 | 44 | if (changedFiles.length === 0) { 45 | this.skipNextSync = true; 46 | } 47 | 48 | if (this.skipNextSync) { 49 | this.hooks.syncSkipped.call(changedFiles, stats); 50 | } else { 51 | this.hooks.sync.call(changedFiles, stats); 52 | 53 | const { 54 | outputOptions: { path: outputPath }, 55 | } = stats.compilation; 56 | 57 | await this.deployPendingFiles(outputPath, themekitFlags); 58 | this.skipNextSync = false; 59 | this.hooks.syncDone.call(changedFiles, stats); 60 | } 61 | 62 | this.hooks.afterSync.promise(changedFiles, stats); 63 | 64 | this.skipNextSync = false; 65 | } 66 | 67 | async deployPendingFiles( 68 | compiledOutputPath: string, 69 | themekitFlags: ThemeKitFlags 70 | ) { 71 | const flags: ThemeKitFlags = { 72 | ...themekitFlags, 73 | files: this.filesPendingDeploy, 74 | }; 75 | 76 | await runThemekitCommand('deploy', flags, { cwd: compiledOutputPath }); 77 | 78 | this.filesPendingDeploy = []; 79 | this.isDeploymentInProgress = false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/local-development-server/index.ts: -------------------------------------------------------------------------------- 1 | export * from './local-development-server'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/local-development-server/ssl/server-ssl.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as os from 'os'; 3 | import { existsSync, readFileSync } from 'fs'; 4 | 5 | export interface SslKeyCert { 6 | key: Buffer; 7 | cert: Buffer; 8 | } 9 | 10 | export function getSslKeyCert(): SslKeyCert { 11 | const key = readFileSync(getSSLKeyPath()); 12 | const cert = readFileSync(getSSLCertPath()); 13 | 14 | return { key, cert }; 15 | } 16 | 17 | export function getSSLKeyPath(): string { 18 | const key = path.resolve(os.homedir(), '.localhost_ssl/server.key'); 19 | return existsSync(key) ? key : path.join(__dirname, './server.pem'); 20 | } 21 | 22 | export function getSSLCertPath(): string { 23 | const cert = path.resolve(os.homedir(), '.localhost_ssl/server.crt'); 24 | return existsSync(cert) ? cert : path.join(__dirname, './server.pem'); 25 | } 26 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/ng-compat.ts: -------------------------------------------------------------------------------- 1 | import { convertNxExecutor } from '@nrwl/devkit'; 2 | import { serveExecutor } from './serve.executor'; 3 | 4 | export default convertNxExecutor(serveExecutor); 5 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ServeExecutorSchema { 2 | buildTarget: string; 3 | themekitEnv: string; 4 | open: boolean; 5 | allowLive: boolean; 6 | analyze?: boolean; 7 | skipFirstDeploy: boolean; 8 | devServerIpAddress: string; 9 | proxyConfig?: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/executors/serve/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "title": "Serve executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": { 8 | "buildTarget": { 9 | "type": "string", 10 | "description": "Name of the target to be used in the theme build process." 11 | }, 12 | "analyze": { 13 | "type": "boolean", 14 | "description": "Analyze the generated bundle and open webpack-bundle-analyzer in the browser", 15 | "default": false 16 | }, 17 | "themekitEnv": { 18 | "type": "string", 19 | "description": "Name of the themekit config.yml environment to be used in the deployment", 20 | "default": "development" 21 | }, 22 | "allowLive": { 23 | "type": "boolean", 24 | "description": "Enables making changes to the Shopify Live Theme", 25 | "default": false 26 | }, 27 | "open": { 28 | "type": "boolean", 29 | "description": "Open theme preview in the broswer when the deployment is done.", 30 | "default": false, 31 | "alias": "o" 32 | }, 33 | "skipFirstDeploy": { 34 | "type": "boolean", 35 | "description": "Tell if the first deploy should be skipped.", 36 | "default": false 37 | }, 38 | "devServerIpAddress": { 39 | "type": "string", 40 | "description": "Set the local web server ip address. Valid values are: private (default), public, , ", 41 | "default": "private" 42 | }, 43 | "proxyConfig": { 44 | "type": "string", 45 | "description": "Path to the proxy configuration file to be used" 46 | } 47 | }, 48 | "additionalProperties": false, 49 | "required": ["buildTarget"] 50 | } 51 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/init/init.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { readJson, Tree, WorkspaceJsonConfiguration } from '@nrwl/devkit'; 2 | import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; 3 | import { 4 | autoprefixerVersion, 5 | postcssCombineMediaQueryVersion, 6 | } from '../../utils/versions'; 7 | import { nxShopifyInitGenerator } from './init.generator'; 8 | import { InitGeneratorSchema } from './schema'; 9 | 10 | describe('init', () => { 11 | let tree: Tree; 12 | 13 | beforeEach(() => { 14 | tree = createTreeWithEmptyWorkspace(); 15 | }); 16 | 17 | it('should update default collection', async () => { 18 | const initOptions: InitGeneratorSchema = { skipFormat: false }; 19 | 20 | await nxShopifyInitGenerator(tree, initOptions); 21 | const workspaceJson = readJson( 22 | tree, 23 | '/workspace.json' 24 | ); 25 | 26 | expect(workspaceJson.cli?.defaultCollection).toEqual( 27 | '@trafilea/nx-shopify' 28 | ); 29 | }); 30 | 31 | it('should update package.json', async () => { 32 | const initOptions: InitGeneratorSchema = { skipFormat: false }; 33 | 34 | await nxShopifyInitGenerator(tree, initOptions); 35 | const packageJson = readJson(tree, '/package.json'); 36 | 37 | expect(packageJson.devDependencies).toEqual( 38 | expect.objectContaining({ 39 | autoprefixer: autoprefixerVersion, 40 | 'postcss-combine-media-query': postcssCombineMediaQueryVersion, 41 | }) 42 | ); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/init/init.generator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | addDependenciesToPackageJson, 3 | convertNxGenerator, 4 | formatFiles, 5 | GeneratorCallback, 6 | Tree, 7 | } from '@nrwl/devkit'; 8 | import { jestInitGenerator } from '@nrwl/jest'; 9 | import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; 10 | import { setDefaultCollection } from '@nrwl/workspace/src/utilities/set-default-collection'; 11 | import { 12 | autoprefixerVersion, 13 | documentReadyVersion, 14 | postcssCombineMediaQueryVersion, 15 | } from '../../utils/versions'; 16 | import { InitGeneratorSchema } from './schema'; 17 | 18 | function updateDependencies(tree: Tree) { 19 | return addDependenciesToPackageJson( 20 | tree, 21 | { 22 | 'document-ready': documentReadyVersion, 23 | }, 24 | { 25 | autoprefixer: autoprefixerVersion, 26 | 'postcss-combine-media-query': postcssCombineMediaQueryVersion, 27 | } 28 | ); 29 | } 30 | 31 | export async function nxShopifyInitGenerator( 32 | host: Tree, 33 | schema: InitGeneratorSchema 34 | ) { 35 | setDefaultCollection(host, '@trafilea/nx-shopify'); 36 | 37 | const tasks: GeneratorCallback[] = []; 38 | 39 | if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { 40 | const jestTask = jestInitGenerator(host, {}); 41 | tasks.push(jestTask); 42 | } 43 | 44 | const updateDepsTask = updateDependencies(host); 45 | tasks.push(updateDepsTask); 46 | 47 | if (!schema.skipFormat) { 48 | await formatFiles(host); 49 | } 50 | return runTasksInSerial(...tasks); 51 | } 52 | 53 | export default nxShopifyInitGenerator; 54 | export const nxShopifyInitSchematic = convertNxGenerator( 55 | nxShopifyInitGenerator 56 | ); 57 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/init/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface InitGeneratorSchema { 2 | unitTestRunner?: 'jest' | 'none'; 3 | skipFormat?: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/init/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "id": "NxShopifyInit", 4 | "cli": "nx", 5 | "title": "Init Nx-Shopify Plugin", 6 | "type": "object", 7 | "properties": { 8 | "unitTestRunner": { 9 | "description": "Adds the specified unit test runner.", 10 | "type": "string", 11 | "enum": ["jest", "none"], 12 | "default": "jest" 13 | }, 14 | "skipFormat": { 15 | "description": "Skip formatting files", 16 | "type": "boolean", 17 | "default": false 18 | } 19 | }, 20 | "required": [] 21 | } 22 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/files/__fileName__.layout.scss__template__: -------------------------------------------------------------------------------- 1 | .layout-elements { 2 | margin: 3em 0; 3 | } 4 | 5 | @media screen and (min-width: 460px) { 6 | .layout-elements { 7 | margin: 2em 0; 8 | } 9 | } 10 | 11 | @media screen and (min-width: 1024px) { 12 | .layout-elements { 13 | margin: 1em 0; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/files/__fileName__.layout.spec.ts__template__: -------------------------------------------------------------------------------- 1 | import { <%= className %>Layout } from './<%= fileName %>.layout'; 2 | 3 | describe('<%= className %>Layout', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let <%= propertyName %>Layout: <%= className %>Layout; 7 | 8 | beforeEach(() => { 9 | <%= propertyName %>Layout = new <%= className %>Layout(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(<%= propertyName %>Layout).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(<%= propertyName %>Layout.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/files/__fileName__.layout.ts__template__: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './<%= fileName %>.layout.scss'; 8 | 9 | export class <%= className %>Layout extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('<%= className %> Layout: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/files/__fileName__.liquid__template__: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page_title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {%- if settings.favicon != blank -%} 12 | 13 | {%- endif -%} 14 | 15 | {% render 'script-tags' %} 16 | {% render 'style-tags' %} 17 | 18 | {{ content_for_header }} 19 | 20 | 21 | 22 | {% section 'header' %} 23 | 24 | {% for link in linklists.main-menu.links %} 25 | {% assign child_list_handle = link.title | handleize %} 26 | {% if linklists[child_list_handle].links != blank %} 27 | {{ link.title }} 28 | [{% for childlink in linklists[child_list_handle].links %} 29 | {{ childlink.title | escape }} 30 | {% endfor %}] 31 | {% else %} 32 | {{ link.title }} 33 | {% endif %} 34 | {% endfor %} 35 | 36 | cart 37 | 38 | {% if shop.customer_accounts_enabled %} 39 | {% if customer %} 40 | account 41 | {{ 'log out' | customer_logout_link }} 42 | {% else %} 43 | {{ 'log in' | customer_login_link }} 44 | {{ 'register' | customer_register_link }} 45 | {% endif %} 46 | {% endif %} 47 | 48 |
49 | {{ content_for_layout }} 50 |
51 | 52 | {% section 'footer' %} 53 | 54 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/layout.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nrwl/devkit'; 3 | 4 | import generator from './layout.generator'; 5 | import { LayoutGeneratorSchema } from './schema'; 6 | 7 | describe('layout generator', () => { 8 | let appTree: Tree; 9 | const options: LayoutGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface LayoutGeneratorSchema { 2 | name: string; 3 | project: string; 4 | directory?: string; 5 | tags?: string; 6 | directory?: string; 7 | flat?: boolean; 8 | liquidOnly?: boolean; 9 | skipTests?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/layout/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "id": "NxShopifyLayout", 5 | "title": "Create a Shopify Theme layout for Nx", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "The name of the new theme layout", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "project": { 18 | "type": "string", 19 | "description": "The name of the project where the layout will be generated.", 20 | "alias": "p", 21 | "$default": { 22 | "$source": "projectName" 23 | }, 24 | "x-prompt": "What is the name of the project for this layout?" 25 | }, 26 | "directory": { 27 | "type": "string", 28 | "description": "Create the layout under this directory relative to src/theme/layout (can be nested).", 29 | "alias": "d" 30 | }, 31 | "flat": { 32 | "type": "boolean", 33 | "description": "Create layout files at the directory root rather than its own directory.", 34 | "default": false 35 | }, 36 | "liquidOnly": { 37 | "type": "boolean", 38 | "description": "When true, does not create files other than the liquid file for the new layout.", 39 | "default": false 40 | }, 41 | "skipTests": { 42 | "type": "boolean", 43 | "description": "When true, does not create \"spec.ts\" test files for the new layout.", 44 | "default": false 45 | } 46 | }, 47 | "required": ["name", "project"] 48 | } 49 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/files/__fileName__.liquid__template__: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {% schema %} 5 | { 6 | "name": "<%= className %>", 7 | "settings": [ 8 | ] 9 | {% endschema %} -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/files/__fileName__.section.scss__template__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/section/files/__fileName__.section.scss__template__ -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/files/__fileName__.section.spec.ts__template__: -------------------------------------------------------------------------------- 1 | import { <%= className %>Section } from './<%= fileName %>.section'; 2 | 3 | describe('<%= className %>Section', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const <%= propertyName %>Section = new <%= className %>Section(); 7 | 8 | expect(<%= propertyName %>Section).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/files/__fileName__.section.ts__template__: -------------------------------------------------------------------------------- 1 | import './<%= fileName %>.section.scss'; 2 | 3 | export class <%= className %>Section {} 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface SectionGeneratorSchema { 2 | name: string; 3 | project: string; 4 | directory?: string; 5 | tags?: string; 6 | directory?: string; 7 | flat?: boolean; 8 | liquidOnly?: boolean; 9 | skipTests?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "id": "NxShopifySection", 5 | "title": "Create a Shopify Theme section for Nx", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "The name of the new theme section", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "project": { 18 | "type": "string", 19 | "description": "The name of the project where the section will be generated.", 20 | "alias": "p", 21 | "$default": { 22 | "$source": "projectName" 23 | }, 24 | "x-prompt": "What is the name of the project for this section?" 25 | }, 26 | "directory": { 27 | "type": "string", 28 | "description": "Create the section under this directory relative to src/theme/sections (can be nested).", 29 | "alias": "d" 30 | }, 31 | "flat": { 32 | "type": "boolean", 33 | "description": "Create section files at the directory root rather than its own directory.", 34 | "default": false 35 | }, 36 | "liquidOnly": { 37 | "type": "boolean", 38 | "description": "When true, does not create files other than the liquid file for the new section.", 39 | "default": false 40 | }, 41 | "skipTests": { 42 | "type": "boolean", 43 | "description": "When true, does not create \"spec.ts\" test files for the new section.", 44 | "default": false 45 | } 46 | }, 47 | "required": ["name", "project"] 48 | } 49 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/section/section.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nrwl/devkit'; 3 | 4 | import generator from './generator'; 5 | import { SectionGeneratorSchema } from './schema'; 6 | 7 | describe('section generator', () => { 8 | let appTree: Tree; 9 | const options: SectionGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/files/__fileName__.liquid__template__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/snippet/files/__fileName__.liquid__template__ -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/files/__fileName__.snippet.scss__template__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/snippet/files/__fileName__.snippet.scss__template__ -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/files/__fileName__.snippet.spec.ts__template__: -------------------------------------------------------------------------------- 1 | import { <%= className %>Snippet } from './<%= fileName %>.snippet'; 2 | 3 | describe('<%= className %>Snippet', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const <%= propertyName %>Snippet = new <%= className %>Snippet(); 7 | 8 | expect(<%= propertyName %>Snippet).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/files/__fileName__.snippet.ts__template__: -------------------------------------------------------------------------------- 1 | import './<%= fileName %>.snippet.scss'; 2 | 3 | export class <%= className %>Snippet {} 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface SnippetGeneratorSchema { 2 | name: string; 3 | project: string; 4 | directory?: string; 5 | tags?: string; 6 | directory?: string; 7 | flat?: boolean; 8 | liquidOnly?: boolean; 9 | skipTests?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "id": "NxShopifySnippet", 5 | "title": "Create a Shopify Theme snippet for Nx", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "The name of the new theme snippet", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "project": { 18 | "type": "string", 19 | "description": "The name of the project where the snippet will be generated.", 20 | "alias": "p", 21 | "$default": { 22 | "$source": "projectName" 23 | }, 24 | "x-prompt": "What is the name of the project for this snippet?" 25 | }, 26 | "directory": { 27 | "type": "string", 28 | "description": "Create the snippet under this directory relative to src/theme/snippets (can be nested).", 29 | "alias": "d" 30 | }, 31 | "flat": { 32 | "type": "boolean", 33 | "description": "Create snippet files at the directory root rather than its own directory.", 34 | "default": false 35 | }, 36 | "liquidOnly": { 37 | "type": "boolean", 38 | "description": "When true, does not create files other than the liquid file for the new snippet.", 39 | "default": false 40 | }, 41 | "skipTests": { 42 | "type": "boolean", 43 | "description": "When true, does not create \"spec.ts\" test files for the new snippet.", 44 | "default": false 45 | } 46 | }, 47 | "required": ["name", "project"] 48 | } 49 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/snippet/snippet.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nrwl/devkit'; 3 | 4 | import generator from './generator'; 5 | import { SnippetGeneratorSchema } from './schema'; 6 | 7 | describe('snippet generator', () => { 8 | let appTree: Tree; 9 | const options: SnippetGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/files/__fileName__.liquid__template__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/template/files/__fileName__.liquid__template__ -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/files/__fileName__.template.scss__template__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/template/files/__fileName__.template.scss__template__ -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/files/__fileName__.template.spec.ts__template__: -------------------------------------------------------------------------------- 1 | import { <%= className %>Template } from './<%= fileName %>.template'; 2 | 3 | describe('<%= className %>Template', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let <%= propertyName %>Template: <%= className %>Template; 7 | 8 | beforeEach(() => { 9 | <%= propertyName %>Template = new <%= className %>Template(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(<%= propertyName %>Template).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(<%= propertyName %>Template.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/files/__fileName__.template.ts__template__: -------------------------------------------------------------------------------- 1 | import { ThemeModule, ThemeContext, ThemeOnReady } from '<%= importPath %>/core'; 2 | 3 | import './<%= fileName %>.template.scss'; 4 | 5 | export class <%= className %>Template extends ThemeModule implements ThemeOnReady { 6 | constructor(context: ThemeContext) { 7 | super(context); 8 | } 9 | 10 | onReady() { 11 | console.log('<%= className %> Template: onReady() called'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface TemplateGeneratorSchema { 2 | name: string; 3 | project: string; 4 | directory?: string; 5 | tags?: string; 6 | directory?: string; 7 | flat?: boolean; 8 | liquidOnly?: boolean; 9 | skipTests?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "id": "NxShopifyTemplate", 5 | "title": "Create a Shopify Theme template for Nx", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "The name of the new theme template", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "project": { 18 | "type": "string", 19 | "description": "The name of the project where the template will be generated.", 20 | "alias": "p", 21 | "$default": { 22 | "$source": "projectName" 23 | }, 24 | "x-prompt": "What is the name of the project for this template?" 25 | }, 26 | "directory": { 27 | "type": "string", 28 | "description": "Create the template under this directory relative to src/theme/templates (can be nested).", 29 | "alias": "d" 30 | }, 31 | "flat": { 32 | "type": "boolean", 33 | "description": "Create template files at the directory root rather than its own directory.", 34 | "default": false 35 | }, 36 | "liquidOnly": { 37 | "type": "boolean", 38 | "description": "When true, does not create files other than the liquid file for the new template.", 39 | "default": false 40 | }, 41 | "skipTests": { 42 | "type": "boolean", 43 | "description": "When true, does not create \"spec.ts\" test files for the new template.", 44 | "default": false 45 | } 46 | }, 47 | "required": ["name", "project"] 48 | } 49 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/template/template.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nrwl/devkit'; 3 | 4 | import generator from './template.generator'; 5 | import { TemplateGeneratorSchema } from './schema'; 6 | 7 | describe('template generator', () => { 8 | let appTree: Tree; 9 | const options: TemplateGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/README.md.template: -------------------------------------------------------------------------------- 1 | # <%= name %> Theme 2 | 3 | This project was generated using [Nx-Shopify](https://github.com/trafilea/nx-shopify), read the documentation at https://trafilea.github.io/nx-shopify. 4 | 5 | ## Configuration 6 | 7 | Configure the themekit's config.yml file according to the [Shopify's Themekit documentation](https://shopify.dev/tools/theme-kit) 8 | 9 | ## Build 10 | 11 | ```bash 12 | nx build <%= projectName %> [options,...] 13 | ``` 14 | 15 | ## Serve 16 | 17 | ```bash 18 | nx serve <%= projectName %> [options,...] 19 | ``` 20 | 21 | ## Deploy 22 | 23 | ```bash 24 | nx deploy <%= projectName %> [options,...] 25 | ``` 26 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/__dot__eslintrc.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["<%= offsetFromRoot %>.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "parserOptions": { 8 | "project": ["<%= projectRoot %>/tsconfig.*?.json"] 9 | }, 10 | "rules": {} 11 | }, 12 | { 13 | "files": ["*.ts", "*.tsx"], 14 | "rules": {} 15 | }, 16 | { 17 | "files": ["*.js", "*.jsx"], 18 | "rules": {} 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/__dot__gitignore.template: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Shopify config file 4 | config.yml -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/browserslist.template: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # If you need to support different browsers in production, you may tweak the list below. 6 | 7 | last 1 Chrome version 8 | last 1 Firefox version 9 | last 2 Edge major versions 10 | last 2 Safari major version 11 | last 2 iOS major versions 12 | Firefox ESR 13 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/config.example.yml.template: -------------------------------------------------------------------------------- 1 | # See https://shopify.github.io/themekit/configuration/ for more about this config file. 2 | 3 | development: 4 | password: 5 | theme_id: "" 6 | store: .myshopify.com 7 | 8 | production: 9 | password: 10 | theme_id: "" 11 | store: .myshopify.com 12 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/config.yml.template: -------------------------------------------------------------------------------- 1 | # See https://shopify.github.io/themekit/configuration/ for more about this config file. 2 | 3 | development: 4 | password: 5 | theme_id: "" 6 | store: .myshopify.com 7 | 8 | production: 9 | password: 10 | theme_id: "" 11 | store: .myshopify.com 12 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/package.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= fileName %>-theme", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "tsc": "tsc -p tsconfig.app.json", 9 | "webpack": "webpack" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "typescript": "^3.9.7", 15 | "webpack": "^4.44.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/postcss.config.js.template: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer'), 4 | require('postcss-combine-media-query'), 5 | ] 6 | } -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/proxy.conf.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "/api": { 3 | "target": "http://localhost:3333", 4 | "secure": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/assets/favicon/__dot__gitkeep.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/assets/favicon/__dot__gitkeep.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/assets/fonts/__dot__gitkeep.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/assets/fonts/__dot__gitkeep.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/assets/images/__dot__gitkeep.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/assets/images/__dot__gitkeep.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/assets/svg/__dot__gitkeep.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/assets/svg/__dot__gitkeep.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/assets/svg/example.svg.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/assets/svg/example.svg.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/config/settings_data.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "current": "Default", 3 | "presets": { 4 | "Default": { 5 | "favicon": "" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './life-cycle'; 2 | export * from './theme-bootstrap'; 3 | export * from './theme-context'; 4 | export * from './theme-module'; 5 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/life-cycle/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './theme-on-ready'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/life-cycle/theme-on-ready.ts.template: -------------------------------------------------------------------------------- 1 | export interface ThemeOnReady { 2 | /** 3 | * A callback method that waits after the DOM has loaded to be 4 | * invoked or invoked immediately if DOM has already loaded. 5 | * It is invoked only once when the module is instantiated. 6 | */ 7 | onReady(): void; 8 | } 9 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/theme-bootstrap.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeGlobalModule } from '../global'; 2 | import { ThemeOnReady } from './life-cycle'; 3 | import { themeBootstrapFactory } from './theme-bootstrap'; 4 | import { ThemeModule } from './theme-module'; 5 | 6 | describe('Theme Bootstrap Process', () => { 7 | const testThemeName = 'TestName'; 8 | const mockThemeContext = { themeName: testThemeName }; 9 | 10 | afterEach(() => jest.resetAllMocks()); 11 | 12 | class MockThemeModule extends ThemeModule implements ThemeOnReady { 13 | onReady() {} 14 | } 15 | it('should load theme modules', async () => { 16 | const loadSpy = jest.spyOn(MockThemeModule, 'load'); 17 | 18 | const themeBootstrap = themeBootstrapFactory( 19 | { theme: () => Promise.resolve(MockThemeModule) }, 20 | { index: () => Promise.resolve(MockThemeModule) } 21 | ); 22 | 23 | await themeBootstrap({ 24 | themeLayoutName: 'theme', 25 | themeTemplateName: 'index', 26 | themeContext: mockThemeContext, 27 | loadGlobal: false, 28 | }); 29 | 30 | expect(loadSpy).toBeCalledWith(mockThemeContext); 31 | expect(loadSpy).toBeCalledTimes(2); 32 | }); 33 | 34 | it('should load global module', async () => { 35 | const loadSpy = jest.spyOn(ThemeGlobalModule, 'load'); 36 | 37 | const themeBootstrap = themeBootstrapFactory({}, {}); 38 | 39 | await themeBootstrap({ 40 | themeLayoutName: '', 41 | themeTemplateName: '', 42 | themeContext: mockThemeContext, 43 | loadGlobal: true, 44 | }); 45 | 46 | expect(loadSpy).toBeCalledWith(mockThemeContext); 47 | expect(loadSpy).toBeCalled(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/theme-bootstrap.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeContext, ThemeModule } from '<%= importPath %>/core'; 2 | import { ThemeGlobalModule } from '<%= importPath %>/global'; 3 | import documentReady from 'document-ready'; 4 | 5 | export interface ShopifyBootstrapOptions { 6 | themeLayoutName: string; 7 | themeTemplateName: string; 8 | themeContext: ThemeContext; 9 | loadGlobal: boolean; 10 | } 11 | 12 | export interface ThemeModuleMapping { 13 | [key: string]: () => Promise; 14 | } 15 | 16 | /** 17 | * This function gets added to the global window and then called 18 | * on page load with the current template loaded and JS Context passed in 19 | * @param pageType String 20 | * @param contextJSON 21 | * @returns {*} 22 | */ 23 | export function themeBootstrapFactory( 24 | registeredLayouts: ThemeModuleMapping, 25 | registeredTemplates: ThemeModuleMapping 26 | ): (options: ShopifyBootstrapOptions) => Promise { 27 | return (options: ShopifyBootstrapOptions) => 28 | new Promise((resolve) => { 29 | const { 30 | themeLayoutName, 31 | themeTemplateName, 32 | themeContext, 33 | loadGlobal = true, 34 | } = options; 35 | const context = themeContext ?? null; 36 | 37 | documentReady(() => { 38 | // Load globals 39 | if (loadGlobal) { 40 | ThemeGlobalModule.load(context); 41 | } 42 | 43 | const importPromises: Array> = []; 44 | 45 | // Find the appropriate template loader based on themeTemplateName 46 | const themeLayoutImporter = registeredLayouts[themeLayoutName]; 47 | if (typeof themeLayoutImporter === 'function') { 48 | importPromises.push(themeLayoutImporter()); 49 | } 50 | 51 | // See if there is a page class default for a custom template 52 | const themeTemplateImporter = registeredTemplates[themeTemplateName]; 53 | if (typeof themeTemplateImporter === 'function') { 54 | importPromises.push(themeTemplateImporter()); 55 | } 56 | 57 | // Wait for imports to resolve, then call load() on them 58 | Promise.all(importPromises).then((moduleImports) => { 59 | moduleImports.forEach((module: typeof ThemeModule) => { 60 | module.load(context); 61 | }); 62 | resolve(); 63 | }); 64 | }); 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/theme-context.ts.template: -------------------------------------------------------------------------------- 1 | export interface ThemeContext { 2 | themeName: string; 3 | } 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/theme-module.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeContext } from '<%= importPath %>/core'; 2 | import { implementsOnReady } from './utils'; 3 | import documenReady from 'document-ready'; 4 | 5 | export class ThemeModule { 6 | constructor(public context: ThemeContext) {} 7 | 8 | static load(context: ThemeContext) { 9 | const themeModule = new this(context); 10 | 11 | if (implementsOnReady(themeModule)) { 12 | documenReady(() => { 13 | themeModule.onReady.bind(themeModule)(); 14 | }); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/utils/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './theme-bootstrap-utils'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/core/utils/theme-bootstrap-utils.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeOnReady } from '../life-cycle'; 2 | import { ThemeModule } from '../theme-module'; 3 | 4 | export function implementsOnReady( 5 | arg: ThemeModule 6 | ): arg is ThemeModule & ThemeOnReady { 7 | return ((arg as unknown) as ThemeOnReady).onReady !== undefined; 8 | } 9 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/environments/environment-schema.ts.template: -------------------------------------------------------------------------------- 1 | export interface EnvironmentSchema { 2 | production: boolean; 3 | } 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/environments/environment.prod.ts.template: -------------------------------------------------------------------------------- 1 | import { EnvironmentSchema } from './environment-schema'; 2 | 3 | export const environment: EnvironmentSchema = { 4 | production: true, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/environments/environment.ts.template: -------------------------------------------------------------------------------- 1 | import { EnvironmentSchema } from './environment-schema'; 2 | 3 | export const environment: EnvironmentSchema = { 4 | production: false, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/global/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './theme-global-module'; -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/global/theme-global-module.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/global/theme-global-module.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/global/theme-global-module.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeGlobalModule } from './theme-global-module'; 2 | 3 | describe('ThemeGlobalModule', () => { 4 | const testThemeName = 'TestName'; 5 | 6 | it('should initiate successfully', () => { 7 | const globalModule = new ThemeGlobalModule({ themeName: testThemeName }); 8 | 9 | expect(globalModule).toBeTruthy(); 10 | expect(globalModule.context.themeName).toEqual(testThemeName); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/global/theme-global-module.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeModule } from '<%= importPath %>/core/theme-module'; 2 | import { ThemeContext } from '<%= importPath %>/core/theme-context'; 3 | import { ThemeOnReady } from '<%= importPath %>/core/life-cycle'; 4 | 5 | import './theme-global-module.scss'; 6 | 7 | export class ThemeGlobalModule extends ThemeModule implements ThemeOnReady { 8 | constructor(context: ThemeContext) { 9 | super(context); 10 | } 11 | 12 | onReady() { 13 | console.log('Theme Global Module: onReady() called'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/locales/en.default.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "general": { 3 | "404": { 4 | "title": "Not found", 5 | "subtext_html": "The page you were looking for does not exist" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/main.ts.template: -------------------------------------------------------------------------------- 1 | __webpack_public_path__ = window['__webpack_public_path__']; 2 | 3 | import { themeBootstrapFactory } from '<%= importPath %>/core/theme-bootstrap'; 4 | import { themeLayouts } from '<%= importPath %>/theme/layout'; 5 | import { themeTemplates } from '<%= importPath %>/theme/templates'; 6 | 7 | window['themeBootstrap'] = themeBootstrapFactory( 8 | themeLayouts, 9 | themeTemplates 10 | ); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './theme-layouts'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/theme-layouts.ts.template: -------------------------------------------------------------------------------- 1 | export const themeLayouts = { 2 | theme: () => import('./theme/theme.layout').then((m) => m.ThemeLayout), 3 | }; 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/theme/theme.layout.scss.template: -------------------------------------------------------------------------------- 1 | .layout-elements { 2 | margin: 3em 0; 3 | } 4 | 5 | @media screen and (min-width: 460px) { 6 | .layout-elements { 7 | margin: 2em 0; 8 | } 9 | } 10 | 11 | @media screen and (min-width: 1024px) { 12 | .layout-elements { 13 | margin: 1em 0; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/theme/theme.layout.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ThemeLayout } from './theme.layout'; 2 | 3 | describe('ThemeLayout', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let themeLayout: ThemeLayout; 7 | 8 | beforeEach(() => { 9 | themeLayout = new ThemeLayout(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(themeLayout).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(themeLayout.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/theme/theme.layout.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './theme.layout.scss'; 8 | 9 | export class ThemeLayout extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('<%= className %> | Theme Layout: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/layout/theme/theme.liquid.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page_title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {%- if settings.favicon != blank -%} 12 | 13 | {%- endif -%} 14 | 15 | {% render 'script-tags' %} 16 | {% render 'style-tags' %} 17 | 18 | {{ content_for_header }} 19 | 20 | 21 | 22 | {% section 'header' %} 23 | 24 | {% for link in linklists.main-menu.links %} 25 | {% assign child_list_handle = link.title | handleize %} 26 | {% if linklists[child_list_handle].links != blank %} 27 | {{ link.title }} 28 | [{% for childlink in linklists[child_list_handle].links %} 29 | {{ childlink.title | escape }} 30 | {% endfor %}] 31 | {% else %} 32 | {{ link.title }} 33 | {% endif %} 34 | {% endfor %} 35 | 36 | cart 37 | 38 | {% if shop.customer_accounts_enabled %} 39 | {% if customer %} 40 | account 41 | {{ 'log out' | customer_logout_link }} 42 | {% else %} 43 | {{ 'log in ' | customer_login_link }} 44 | {{ 'register' | customer_register_link }} 45 | {% endif %} 46 | {% endif %} 47 | 48 |
49 | {{ content_for_layout }} 50 |
51 | 52 | {% section 'footer' %} 53 | 54 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/footer/footer.liquid.template: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% for block in section.blocks %} 4 |
5 | {{ block.settings.footer | escape }} 6 |
7 | {% endfor %} 8 |
9 |
10 | {% render 'message' %} 11 | 12 | {% schema %} 13 | { 14 | "name": "Footer", 15 | "max_blocks": 3, 16 | "settings": [], 17 | "blocks": [ 18 | { 19 | "type": "message", 20 | "name": "Bottom message", 21 | "settings": [ 22 | { 23 | "type": "text", 24 | "id": "footer", 25 | "label": "Footer" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | {% endschema %} -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/footer/footer.section.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/sections/footer/footer.section.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/footer/footer.section.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { FooterSection } from './footer.section'; 2 | 3 | describe('FooterSection', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const footerSection = new FooterSection(); 7 | 8 | expect(footerSection).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/footer/footer.section.ts.template: -------------------------------------------------------------------------------- 1 | 2 | import { MessageSnippet } from '../../snippets'; 3 | 4 | export class FooterSection { 5 | message = new MessageSnippet(); 6 | } 7 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/header/header.liquid.template: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% for block in section.blocks %} 4 |
5 | {{ block.settings.heading | escape }} 6 |
7 | {% endfor %} 8 |
9 |
10 | {% render 'message' %} 11 | 12 | {% schema %} 13 | { 14 | "name": "Header", 15 | "max_blocks": 3, 16 | "settings": [], 17 | "blocks": [ 18 | { 19 | "type": "message", 20 | "name": "Store message", 21 | "settings": [ 22 | { 23 | "type": "text", 24 | "id": "heading", 25 | "label": "Heading" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | {% endschema %} -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/header/header.section.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/sections/header/header.section.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/header/header.section.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { HeaderSection } from './header.section'; 2 | 3 | describe('HeaderSection', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const headerSection = new HeaderSection(); 7 | 8 | expect(headerSection).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/header/header.section.ts.template: -------------------------------------------------------------------------------- 1 | import { MessageSnippet } from '../../snippets'; 2 | 3 | export class HeaderSection { 4 | message = new MessageSnippet(); 5 | } 6 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/sections/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './header/header.section'; 2 | export * from './footer/footer.section'; 3 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './message/message.snippet'; -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.liquid.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.liquid.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.snippet.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { MessageBodySnippet } from './message-body.snippet'; 2 | 3 | describe('MessageBodySnippet', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const messageSnippet = new MessageBodySnippet(); 7 | 8 | expect(messageSnippet).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message-body/message-body.snippet.ts.template: -------------------------------------------------------------------------------- 1 | export class MessageBodySnippet {} 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message.liquid.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message.liquid.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message.snippet.scss.template: -------------------------------------------------------------------------------- 1 | .message { 2 | color: black; 3 | } 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message.snippet.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { MessageSnippet } from './message.snippet'; 2 | 3 | describe('MessageSnippet', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const messageSnippet = new MessageSnippet(); 7 | 8 | expect(messageSnippet).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/message/message.snippet.ts.template: -------------------------------------------------------------------------------- 1 | export class MessageSnippet {} 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.liquid.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.liquid.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.snippet.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.snippet.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.snippet.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ProductGallerySnippet } from './product-gallery.snippet'; 2 | 3 | describe('ProductGallerySnippet', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const productGallerySnippet = new ProductGallerySnippet(); 7 | 8 | expect(productGallerySnippet).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-gallery/product-gallery.snippet.ts.template: -------------------------------------------------------------------------------- 1 | export class ProductGallerySnippet {} 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.liquid.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.liquid.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.snippet.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.snippet.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.snippet.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ProductRecommendationsSnippet } from './product-recommendations.snippet'; 2 | 3 | describe('ProductRecommendationsSnippet', () => { 4 | 5 | it('should initiate successfully', () => { 6 | const productRecommendationsSnippet = new ProductRecommendationsSnippet(); 7 | 8 | expect(productRecommendationsSnippet).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/product/product-recommendations/product-recommendations.snippet.ts.template: -------------------------------------------------------------------------------- 1 | export class ProductRecommendationsSnippet {} 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/snippets/theme-context/theme-context.liquid.template: -------------------------------------------------------------------------------- 1 | { 2 | themeName: '{{ theme.name }}', 3 | } -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/404/404.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ 'general.404.title' | t }}

2 |

{{ 'general.404.subtext_html' | t }}

3 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/404/404.template.scss.template: -------------------------------------------------------------------------------- 1 | .title-404 { 2 | border: 1px solid red; 3 | } 4 | 5 | @media print, screen and (min-width: 460px) { 6 | .title-404 { 7 | border: 3px solid magenta; 8 | } 9 | } -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/404/404.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { NotFound404Template } from './404.template'; 2 | 3 | describe('NotFound404Template', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let notFound404Template: NotFound404Template; 7 | 8 | beforeEach(() => { 9 | notFound404Template = new NotFound404Template(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(notFound404Template).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(notFound404Template.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/404/404.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './404.template.scss'; 8 | 9 | export class NotFound404Template extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('404 Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/article/article.liquid.template: -------------------------------------------------------------------------------- 1 | {% assign number_of_comments = article.comments_count %} 2 | {% if comment and comment.created_at %} 3 | {% assign number_of_comments = article.comments_count %} 4 | {% endif %} 5 | 6 |

{{ article.title }}

7 | {% capture author %}{{ article.author }}{% endcapture %} 8 | {% capture date %}{% endcapture %} 9 | {{ article.author }} @ {{ article.created_at }} 10 | 11 |
{{ article.content }}
12 | {% if blog.comments_enabled? %} 13 |

{{ number_of_comments }} comments

14 | {% paginate article.comments by 5 %} 15 | {% for comment in article.comments %} 16 |
17 |
{{ comment.content }}
18 | {{ comment.author }} @ {{ comment.created_at }} 19 |
20 | {% endfor %} 21 | {% if paginate.pages > 1 %} 22 | {{ paginate | default_pagination }} 23 | {% endif %} 24 | {% endpaginate %} 25 | 26 |
27 | {% form 'new_comment', article %} 28 | {{ form.errors | default_errors }} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% endform %} 40 |
41 | {% endif %} 42 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/article/article.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/article/article.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/article/article.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ArticleTemplate } from './article.template'; 2 | 3 | describe('ArticleTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let articleTemplate: ArticleTemplate; 7 | 8 | beforeEach(() => { 9 | articleTemplate = new ArticleTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(articleTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(articleTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/article/article.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './article.template.scss'; 8 | 9 | export class ArticleTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Article Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/blog/blog.liquid.template: -------------------------------------------------------------------------------- 1 | {% paginate blog.articles by 5 %} 2 | 3 |

{{ blog.title }}

4 | {% for article in blog.articles %} 5 |
6 |

{{ article.title }}

7 | {{ article.author }} @ {{ article.created_at }} 8 |
9 | {% if article.excerpt.size > 0 %} 10 | {{ article.excerpt }} 11 | {% else %} 12 |

{{ article.content | strip_html | truncatewords: 100 }}

13 | {% endif %} 14 |
15 |
16 | {% endfor %} 17 | 18 | {% if paginate.pages > 1 %} 19 | {{ paginate | default_pagination }} 20 | {% endif %} 21 | 22 | {% endpaginate %} 23 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/blog/blog.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/blog/blog.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/blog/blog.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { BlogTemplate } from './blog.template'; 2 | 3 | describe('BlogTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let blogTemplate: BlogTemplate; 7 | 8 | beforeEach(() => { 9 | blogTemplate = new BlogTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(blogTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(blogTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/blog/blog.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './blog.template.scss'; 8 | 9 | export class BlogTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Blog Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/cart/cart.liquid.template: -------------------------------------------------------------------------------- 1 | {% if cart.item_count > 0 %} 2 |

My Cart

3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for item in cart.items %} 15 | 16 | 23 | 32 | 40 | 47 | 50 | 51 | {% endfor %} 52 | 53 |
ProductPriceQuantityTotal Price
17 | {% if item.image != blank %} 18 | 19 | {{ item | img_url: '240x240' | img_tag: item.title }} 20 | 21 | {% endif %} 22 | 24 | {{ item.product.title }} 25 | {% unless item.product.has_only_default_variant %} 26 |

{{ item.variant.title }}

27 | {% endunless %} 28 | 29 | Remove 30 | 31 |
33 | {% if item.original_line_price != item.line_price %} 34 | {{ item.price | money }} 35 | {{ item.original_price | money }} 36 | {% else %} 37 | {{ item.price | money }} 38 | {% endif %} 39 | 41 | 46 | 48 | {{ item.line_price | money }} 49 |
54 | 55 |

Subtotal

56 |

{{ cart.total_price | money }}

57 | 58 | 59 | 60 |
61 | {% else %} 62 |

My Cart

63 | {% endif %} 64 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/cart/cart.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/cart/cart.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/cart/cart.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CartTemplate } from './cart.template'; 2 | 3 | describe('CartTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let cartTemplate: CartTemplate; 7 | 8 | beforeEach(() => { 9 | cartTemplate = new CartTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(cartTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(cartTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/cart/cart.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './cart.template.scss'; 8 | 9 | export class CartTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Cart Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection-list/collection-list.liquid.template: -------------------------------------------------------------------------------- 1 | {% paginate collection.products by 2 %} 2 |

{{ collection.title }}

3 | {% for product in collection.products %} 4 |
5 | {{ product.title }} 6 | {{ product.price | money }} 7 | {% unless product.available %}
sold out{% endunless %} 8 | 9 | {{ product.featured_image.alt | escape }} 10 | 11 |
12 | {% else %} 13 |

no matches

14 | {% endfor %} 15 | {% if paginate.pages > 1 %}{{ paginate | default_pagination }}{% endif %} 16 | {% endpaginate %} 17 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection-list/collection-list.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection-list/collection-list.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection-list/collection-list.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CollectionListTemplate } from './collection-list.template'; 2 | 3 | describe('CollectionListTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let collectionListTemplate: CollectionListTemplate; 7 | 8 | beforeEach(() => { 9 | collectionListTemplate = new CollectionListTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(collectionListTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(collectionListTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection-list/collection-list.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './collection-list.template.scss'; 8 | 9 | export class CollectionListTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CollectionList Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection/collection.liquid.template: -------------------------------------------------------------------------------- 1 | {% paginate collection.products by 2 %} 2 |

{{ collection.title }}

3 | {% for product in collection.products %} 4 |
5 | {{ product.title }} 6 | {{ product.price | money }} 7 | {% unless product.available %}
sold out{% endunless %} 8 | 9 | {{ product.featured_image.alt | escape }} 10 | 11 |
12 | {% else %} 13 |

no matches

14 | {% endfor %} 15 | {% if paginate.pages > 1 %} 16 | {{ paginate | default_pagination }} 17 | {% endif %} 18 | {% endpaginate %} 19 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection/collection.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection/collection.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection/collection.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CollectionTemplate } from './collection.template'; 2 | 3 | describe('CollectionTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let collectionTemplate: CollectionTemplate; 7 | 8 | beforeEach(() => { 9 | collectionTemplate = new CollectionTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(collectionTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(collectionTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/collection/collection.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './collection.template.scss'; 8 | 9 | export class CollectionTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Collection Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/account/account.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ 'customer.account.title' | t }}

2 | 3 |

{{ 'customer.orders.title' | t }}

4 | 5 | {% paginate customer.orders by 20 %} 6 | {% if customer.orders.size != 0 %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for order in customer.orders %} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% endfor %} 27 | 28 |
{{ 'customer.orders.order_number' | t }}{{ 'customer.orders.date' | t }}{{ 'customer.orders.payment_status' | t }}{{ 'customer.orders.fulfillment_status' | t }}{{ 'customer.orders.total' | t }}
{{ order.name | link_to: order.customer_url }}{{ order.created_at | date: format: 'month_day_year' }}{{ order.financial_status_label }}{{ order.fulfillment_status_label }}{{ order.total_price | money }}
29 | {% else %} 30 |

{{ 'customer.orders.none' | t }}

31 | {% endif %} 32 | 33 | {% if paginate.pages > 1 %} 34 | {% render 'pagination' %} 35 | {% endif %} 36 | 37 | {% endpaginate %} 38 | 39 |

{{ 'customer.account.details' | t }}

40 | 41 | {{ customer.default_address | format_address }} 42 | 43 | {{ 'customer.account.view_addresses' | t }} ({{ customer.addresses_count }}) 44 | 45 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/account/customers.account.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/account/customers.account.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/account/customers.account.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersAccountTemplate } from './customers.account.template'; 2 | 3 | describe('CustomersAccountTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersAccountTemplate: CustomersAccountTemplate; 7 | 8 | beforeEach(() => { 9 | customersAccountTemplate = new CustomersAccountTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersAccountTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersAccountTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/account/customers.account.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.account.template.scss'; 8 | 9 | export class CustomersAccountTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersAccount Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/activate_account/activate_account.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ 'customer.activate_account.title' | t }}

2 |

{{ 'customer.activate_account.subtext' | t }}

3 | 4 | {% form 'activate_customer_password' %} 5 | {{ form.errors | default_errors }} 6 | 7 |

8 | 11 | 15 |

16 | 17 |

18 | 21 | 25 |

26 | 27 | 28 | 29 | {% endform %} 30 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/activate_account/customers.activate_account.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/activate_account/customers.activate_account.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/activate_account/customers.activate_account.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.activate_account.template.scss'; 8 | 9 | export class CustomersActivateAccountTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersActivateAccount Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/activate_account/customers.active_account.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersActivateAccountTemplate } from './customers.activate_account.template'; 2 | 3 | describe('CustomersActivateAccountTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersActivateAccountTemplate: CustomersActivateAccountTemplate; 7 | 8 | beforeEach(() => { 9 | customersActivateAccountTemplate = new CustomersActivateAccountTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersActivateAccountTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersActivateAccountTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/addresses/customers.addresses.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/addresses/customers.addresses.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/addresses/customers.addresses.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersAddressesTemplate } from './customers.addresses.template'; 2 | 3 | describe('CustomersAddressesTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersAddressesTemplate: CustomersAddressesTemplate; 7 | 8 | beforeEach(() => { 9 | customersAddressesTemplate = new CustomersAddressesTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersAddressesTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersAddressesTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/addresses/customers.addresses.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.addresses.template.scss'; 8 | 9 | export class CustomersAddressesTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersAddresses Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/login/customers.login.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/login/customers.login.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/login/customers.login.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersLoginTemplate } from './customers.login.template'; 2 | 3 | describe('CustomersLoginTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersLoginTemplate: CustomersLoginTemplate; 7 | 8 | beforeEach(() => { 9 | customersLoginTemplate = new CustomersLoginTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersLoginTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersLoginTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/login/customers.login.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.login.template.scss'; 8 | 9 | export class CustomersLoginTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersLogin Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/order/customers.order.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/order/customers.order.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/order/customers.order.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersOrderTemplate } from './customers.order.template'; 2 | 3 | describe('CustomersOrderTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersOrderTemplate: CustomersOrderTemplate; 7 | 8 | beforeEach(() => { 9 | customersOrderTemplate = new CustomersOrderTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersOrderTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersOrderTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/order/customers.order.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.order.template.scss'; 8 | 9 | export class CustomersOrderTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersOrder Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/register/customers.register.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/register/customers.register.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/register/customers.register.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersRegisterTemplate } from './customers.register.template'; 2 | 3 | describe('CustomersRegisterTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersRegisterTemplate: CustomersRegisterTemplate; 7 | 8 | beforeEach(() => { 9 | customersRegisterTemplate = new CustomersRegisterTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersRegisterTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersRegisterTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/register/customers.register.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.register.template.scss'; 8 | 9 | export class CustomersRegisterTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersRegister Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/register/register.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ 'customer.register.title' | t }}

2 | 3 | {% form 'create_customer' %} 4 | {{ form.errors | default_errors }} 5 | 6 | 9 | 15 | 16 | 19 | 24 | 25 | 28 | 37 | 38 | 41 | 46 | 47 |

48 | 49 |

50 | {{ 'customer.register.cancel' | t }} 51 | {% endform %} 52 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/reset_password/customers.reset_password.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/reset_password/customers.reset_password.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/reset_password/customers.reset_password.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { CustomersResetPasswordTemplate } from './customers.reset_password.template'; 2 | 3 | describe('CustomersResetPasswordTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let customersResetPasswordTemplate: CustomersResetPasswordTemplate; 7 | 8 | beforeEach(() => { 9 | customersResetPasswordTemplate = new CustomersResetPasswordTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(customersResetPasswordTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(customersResetPasswordTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/reset_password/customers.reset_password.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './customers.reset_password.template.scss'; 8 | 9 | export class CustomersResetPasswordTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('CustomersResetPassword Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/customers/reset_password/reset_password.liquid.template: -------------------------------------------------------------------------------- 1 |
2 | {% form 'reset_customer_password' %} 3 | 4 |

{{ 'customer.reset_password.title' | t }}

5 | 6 |

{{ 'customer.reset_password.subtext' | t: email: email }}

7 | 8 | {{ form.errors | default_errors }} 9 | 10 | 13 | 18 | 19 | 22 | 27 | 28 | 29 | {% endform %} 30 |
31 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/gift_card/gift_card.liquid.template: -------------------------------------------------------------------------------- 1 | {% layout none %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ 'vendor/qrcode.js' | shopify_asset_url | script_tag }} 9 | 10 | 11 |
12 | 19 |
20 | {% if gift_card.pass_url %} 21 | 22 | Add To Apple Wallet 23 | 24 | {% endif %} 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/gift_card/gift_card.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/gift_card/gift_card.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/gift_card/gift_card.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { GiftCardTemplate } from './gift_card.template'; 2 | 3 | describe('GiftCardTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let giftCardTemplate: GiftCardTemplate; 7 | 8 | beforeEach(() => { 9 | giftCardTemplate = new GiftCardTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(giftCardTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(giftCardTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/gift_card/gift_card.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './gift_card.template.scss'; 8 | 9 | export class GiftCardTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('GiftCard Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './theme-templates'; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/index/index.liquid.template: -------------------------------------------------------------------------------- 1 | {% for product in collections.frontpage.products limit:4 %} 2 |
3 | {{ product.title }} 4 | {{ product.price | money }} 5 | {% unless product.available %}
sold out{% endunless %} 6 | 7 | {{ product.featured_image.alt | escape }} 8 | 9 |
10 | {% endfor %} 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/index/index.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/index/index.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/index/index.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { IndexTemplate } from './index.template'; 2 | 3 | describe('IndexTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let indexTemplate: IndexTemplate; 7 | 8 | beforeEach(() => { 9 | indexTemplate = new IndexTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(indexTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(indexTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/index/index.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './index.template.scss'; 8 | 9 | export class IndexTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Index Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/list-collections/list-collections.liquid.template: -------------------------------------------------------------------------------- 1 | {% for collection in collections %} 2 | {% unless collection.handle == 'frontpage' %} 3 | {% capture collection_title %}{{ collection.title | escape }}{% endcapture %} 4 | More {{ collection_title }} › 5 | {% for product in collection.products limit:5 %} 6 | {% assign grid_item_width = 'large--one-fifth medium--one-half' %} 7 |
8 | {{ product.title }} 9 | {{ product.price | money }} 10 | {% unless product.available %}
sold out{% endunless %} 11 | 12 | {{ product.featured_image.alt | escape }} 13 | 14 |
15 | {% endfor %} 16 | {% endunless %} 17 | {% endfor %} 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/list-collections/list-collections.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/list-collections/list-collections.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/list-collections/list-collections.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ListCollectionsTemplate } from './list-collections.template'; 2 | 3 | describe('ListCollectionsTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let listCollectionsTemplate: ListCollectionsTemplate; 7 | 8 | beforeEach(() => { 9 | listCollectionsTemplate = new ListCollectionsTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(listCollectionsTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(listCollectionsTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/list-collections/list-collections.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './list-collections.template.scss'; 8 | 9 | export class ListCollectionsTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('ListCollections Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page-contact/page-contact.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ page.title }}

2 | {% form 'contact' %} 3 | {% if form.posted_successfully? %} Thank you for your contact {% endif %} 4 | {{ form.errors | default_errors }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% endform %} 15 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page-contact/page-contact.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/page-contact/page-contact.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page-contact/page-contact.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { PageContactTemplate } from './page-contact.template'; 2 | 3 | describe('PageContactTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let pageContactTemplate: PageContactTemplate; 7 | 8 | beforeEach(() => { 9 | pageContactTemplate = new PageContactTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(pageContactTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(pageContactTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page-contact/page-contact.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './page-contact.template.scss'; 8 | 9 | export class PageContactTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('PageContact Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page/page.liquid.template: -------------------------------------------------------------------------------- 1 |

{{ page.title }}

2 |
{{ page.content }}
3 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page/page.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/page/page.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page/page.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { PageTemplate } from './page.template'; 2 | 3 | describe('PageTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let pageTemplate: PageTemplate; 7 | 8 | beforeEach(() => { 9 | pageTemplate = new PageTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(pageTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(pageTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/page/page.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './page.template.scss'; 8 | 9 | export class PageTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Page Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/product/product.liquid.template: -------------------------------------------------------------------------------- 1 | {% assign current_variant = product.selected_or_first_available_variant %} 2 | {% assign featured_image = current_variant.featured_image | default: product.featured_image %} 3 | {{ featured_image.alt | escape }} 4 | {% for image in product.images %} 5 | 6 | {{ image.alt | escape }} 7 | 8 | {% endfor %} 9 |

{{ product.title }}

10 |
11 | 24 | {{ current_variant.price | money }} 25 | 26 | 27 | 28 |
29 |
{{ product.description }}
30 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/product/product.template.scss.template: -------------------------------------------------------------------------------- 1 | .product-form { 2 | border: 1px solid pink; 3 | } 4 | 5 | @media print, screen and (min-width: 460px) { 6 | .product-form { 7 | background: green; 8 | } 9 | } -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/product/product.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { ProductTemplate } from './product.template'; 2 | 3 | describe('ProductTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let productTemplate: ProductTemplate; 7 | 8 | beforeEach(() => { 9 | productTemplate = new ProductTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(productTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(productTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/product/product.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './product.template.scss'; 8 | 9 | export class ProductTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Product Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/search/search.liquid.template: -------------------------------------------------------------------------------- 1 | {% paginate search.results by 10 %} 2 |
3 | 4 | 5 |
6 | 7 | {% if search.performed %} 8 | {% for item in search.results %} 9 | {% if item.featured_image %} 10 | 11 | {{ item.featured_image.src | img_url: 'medium' | img_tag: item.featured_image.alt }} 12 | 13 | {% endif %} 14 |
{{ item.title | link_to: item.url }}
15 |

{{ item.content | strip_html | truncatewords: 50 }}

16 | {% else %} 17 | no results 18 | {% endfor %} 19 | {% endif %} 20 | 21 | {% if paginate.pages > 1 %}{{ paginate | default_pagination }}{% endif %} 22 | {% endpaginate %} 23 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/search/search.template.scss.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/generators/theme/files/src/theme/templates/search/search.template.scss.template -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/search/search.template.spec.ts.template: -------------------------------------------------------------------------------- 1 | import { SearchTemplate } from './search.template'; 2 | 3 | describe('SearchTemplate', () => { 4 | const mockThemeContext = { themeName: 'TestName' }; 5 | 6 | let searchTemplate: SearchTemplate; 7 | 8 | beforeEach(() => { 9 | searchTemplate = new SearchTemplate(mockThemeContext); 10 | }); 11 | 12 | it('should initiate successfully', () => { 13 | expect(searchTemplate).toBeTruthy(); 14 | }); 15 | 16 | it('should not mutate the context', () => { 17 | expect(searchTemplate.context).toMatchObject(mockThemeContext); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/search/search.template.ts.template: -------------------------------------------------------------------------------- 1 | import { 2 | ThemeModule, 3 | ThemeContext, 4 | ThemeOnReady, 5 | } from '<%= importPath %>/core'; 6 | 7 | import './search.template.scss'; 8 | 9 | export class SearchTemplate extends ThemeModule implements ThemeOnReady { 10 | constructor(context: ThemeContext) { 11 | super(context); 12 | } 13 | 14 | onReady() { 15 | console.log('Search Template: onReady() called'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/theme/templates/theme-templates.ts.template: -------------------------------------------------------------------------------- 1 | export const themeTemplates = { 2 | '404': () => import('./404/404.template').then((m) => m.NotFound404Template), 3 | article: () => 4 | import('./article/article.template').then((m) => m.ArticleTemplate), 5 | blog: () => import('./blog/blog.template').then((m) => m.BlogTemplate), 6 | cart: () => 7 | import('./cart/cart.template').then( 8 | (m) => m.CartTemplate 9 | ), 10 | collection: () => 11 | import('./collection/collection.template').then( 12 | (m) => m.CollectionTemplate 13 | ), 14 | 'collection-list': () => 15 | import('./collection-list/collection-list.template').then( 16 | (m) => m.CollectionListTemplate 17 | ), 18 | 'customers.account': () => 19 | import('./customers/account/customers.account.template').then( 20 | (m) => m.CustomersAccountTemplate 21 | ), 22 | 'customers.activate_account': () => 23 | import( 24 | './customers/activate_account/customers.activate_account.template' 25 | ).then((m) => m.CustomersActivateAccountTemplate), 26 | 'customers.addresses': () => 27 | import('./customers/addresses/customers.addresses.template').then( 28 | (m) => m.CustomersAddressesTemplate 29 | ), 30 | 'customers.login': () => 31 | import('./customers/login/customers.login.template').then( 32 | (m) => m.CustomersLoginTemplate 33 | ), 34 | 'customers.order': () => 35 | import('./customers/order/customers.order.template').then( 36 | (m) => m.CustomersOrderTemplate 37 | ), 38 | 'customers.register': () => 39 | import('./customers/register/customers.register.template').then( 40 | (m) => m.CustomersRegisterTemplate 41 | ), 42 | 'customers.reset_password': () => 43 | import('./customers/reset_password/customers.reset_password.template').then( 44 | (m) => m.CustomersResetPasswordTemplate 45 | ), 46 | gift_card: () => 47 | import('./gift_card/gift_card.template').then((m) => m.GiftCardTemplate), 48 | index: () => import('./index/index.template').then((m) => m.IndexTemplate), 49 | 'list-collections': () => 50 | import('./list-collections/list-collections.template').then( 51 | (m) => m.ListCollectionsTemplate 52 | ), 53 | page: () => import('./page/page.template').then((m) => m.PageTemplate), 54 | 'page-contact': () => 55 | import('./page-contact/page-contact.template').then( 56 | (m) => m.PageContactTemplate 57 | ), 58 | product: () => 59 | import('./product/product.template').then((m) => m.ProductTemplate), 60 | search: () => import('./search/search.template').then((m) => m.SearchTemplate), 61 | }; 62 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/src/typings.d.ts.template: -------------------------------------------------------------------------------- 1 | declare let __webpack_public_path__: string; 2 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/tsconfig.app.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "<%= offsetFromRoot %>dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], 8 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/tsconfig.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "<%= offsetFromRoot %>tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "esModuleInterop": true, 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "files": [], 9 | "include": [], 10 | "references": [ 11 | { 12 | "path": "./tsconfig.app.json" 13 | }, 14 | { 15 | "path": "./tsconfig.spec.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/files/tsconfig.spec.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "<%= offsetFromRoot %>dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/lib/add-jest.ts: -------------------------------------------------------------------------------- 1 | import { Tree } from '@nrwl/devkit'; 2 | import { jestProjectGenerator } from '@nrwl/jest'; 3 | import { NormalizedSchema } from '../schema'; 4 | 5 | export async function addJest(host: Tree, options: NormalizedSchema) { 6 | if (options.unitTestRunner !== 'jest') { 7 | return () => {}; 8 | } 9 | 10 | return await jestProjectGenerator(host, { 11 | project: options.projectName, 12 | supportTsx: true, 13 | skipSerializers: true, 14 | setupFile: 'none', 15 | babelJest: false, 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ThemeGeneratorSchema { 2 | name: string; 3 | tags?: string; 4 | directory?: string; 5 | skipFormat?: boolean; 6 | unitTestRunner: 'jest' | 'none'; 7 | skipTests?: boolean; 8 | } 9 | 10 | interface NormalizedSchema extends ThemeGeneratorSchema { 11 | importPath: string; 12 | npmScope: string; 13 | projectName: string; 14 | projectRoot: string; 15 | projectDirectory: string; 16 | parsedTags: string[]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/generators/theme/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "id": "NxShopifyTheme", 4 | "cli": "nx", 5 | "title": "Create a Shopify Theme for Nx", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "The name of the new Shopify theme", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "tags": { 18 | "type": "string", 19 | "description": "Add tags to the project (used for linting)", 20 | "alias": "t" 21 | }, 22 | "directory": { 23 | "type": "string", 24 | "description": "A directory where the project is placed", 25 | "alias": "d" 26 | }, 27 | "unitTestRunner": { 28 | "type": "string", 29 | "enum": ["jest", "none"], 30 | "description": "Test runner to use for unit tests.", 31 | "default": "jest" 32 | }, 33 | "skipFormat": { 34 | "description": "Skip formatting files", 35 | "type": "boolean", 36 | "default": false 37 | }, 38 | "skipTests": { 39 | "type": "boolean", 40 | "description": "When true, does not create \"spec.ts\" test files for the new theme.", 41 | "default": false 42 | } 43 | }, 44 | "required": ["name"] 45 | } 46 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/packages/nx-shopify/src/index.ts -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/config-utils.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | 3 | export function getProxyConfig(root: string, proxyConfigPath: string) { 4 | const proxyPath = resolve(root, proxyConfigPath); 5 | return require(proxyPath); 6 | } 7 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/generator-utils.ts: -------------------------------------------------------------------------------- 1 | import { getThemeLiquidFiles, LiquidFileType } from './shopify'; 2 | 3 | export function assertValidGeneratorNameOption( 4 | name: string, 5 | directory: string, 6 | generatorName: string 7 | ) { 8 | const slashes = ['/', '\\']; 9 | slashes.forEach((slash) => { 10 | if (name.indexOf(slash) !== -1) { 11 | const [nameSuggestion, ...rest] = name.split(slash).reverse(); 12 | let directorySuggestion = rest.map((x) => x.toLowerCase()).join(slash); 13 | if (directory) { 14 | directorySuggestion = `${directory}${slash}${directorySuggestion}`; 15 | } 16 | throw new Error( 17 | `Found "${slash}" in the ${generatorName} name. ` + 18 | `Did you mean to use the --directory option (e.g. \`nx g ${generatorName} ${nameSuggestion} --directory ${directorySuggestion}\`)?` 19 | ); 20 | } 21 | }); 22 | } 23 | 24 | export function assertUniqueLiquidFileNameOption( 25 | liquidFileBaseName: string, 26 | liquidFileType: LiquidFileType, 27 | themeBaseDirectory: string 28 | ) { 29 | const liquidFiles = getThemeLiquidFiles( 30 | liquidFileBaseName, 31 | liquidFileType, 32 | themeBaseDirectory 33 | ); 34 | 35 | if (liquidFiles.length > 0) { 36 | const liquidFileTypeSuggestion = liquidFileType.endsWith('s') 37 | ? liquidFileType.slice(0, -1) 38 | : liquidFileType; 39 | 40 | throw new Error( 41 | `A ${liquidFileBaseName}.liquid ${liquidFileTypeSuggestion} already exists in your theme ` + 42 | `(${liquidFiles[0]}). ` + 43 | `A ${liquidFileTypeSuggestion} name should be unique.` 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/local-server/network-utils.ts: -------------------------------------------------------------------------------- 1 | import { promisify } from 'util'; 2 | import * as portscanner from 'portscanner'; 3 | import * as ip from 'ip'; 4 | 5 | const findAPortInUse = promisify(portscanner.findAPortInUse); 6 | 7 | export function getAvailablePortSeries(start, quantity, increment = 1) { 8 | const startPort = start; 9 | const endPort = start + (quantity - 1); 10 | 11 | return findAPortInUse(startPort, endPort, '127.0.0.1').then((port) => { 12 | if (typeof port === 'number') { 13 | return getAvailablePortSeries(port + increment, quantity); 14 | } 15 | 16 | return [...Array(quantity).keys()].map((i) => i + start); 17 | }); 18 | } 19 | 20 | export function getIpAddress(ipAddressValue = 'private') { 21 | if (ip.isV4Format(ipAddressValue) || ip.isV6Format(ipAddressValue)) { 22 | return ipAddressValue; 23 | } 24 | 25 | return ip.address(ipAddressValue); 26 | } 27 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/output-dir-utils.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import * as rimraf from 'rimraf'; 3 | 4 | /** 5 | * Delete an output directory, but error out if it's the root of the project. 6 | */ 7 | export function deleteOutputDir(root: string, outputPath: string) { 8 | const resolvedOutputPath = resolve(root, outputPath); 9 | if (resolvedOutputPath === root) { 10 | throw new Error('Output path MUST not be project root directory!'); 11 | } 12 | 13 | rimraf.sync(resolvedOutputPath); 14 | } 15 | 16 | /** 17 | * Generate a unique name for running CLI commands 18 | * @param prefix 19 | * 20 | * @returns `''` 21 | */ 22 | export function uniq(prefix) { 23 | return `${prefix}${Math.floor(Math.random() * 10000000)}`; 24 | } 25 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/shopify/index.ts: -------------------------------------------------------------------------------- 1 | export * from './shopify-api-models'; 2 | export * from './shopify-api-utils'; 3 | export * from './shopify-theme-utils'; 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/shopify/shopify-api-models.ts: -------------------------------------------------------------------------------- 1 | export interface ShopifyThemeDTO { 2 | id: number; 3 | name: string; 4 | created_at: string; 5 | updated_at: string; 6 | role: string; 7 | theme_store_id: string; 8 | previewable: boolean; 9 | processing: boolean; 10 | admin_graphql_api_id: string; 11 | } 12 | 13 | export interface ShopifyThemesResponse { 14 | themes: ShopifyThemeDTO[]; 15 | errors?: string; 16 | } 17 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/shopify/shopify-api-utils.ts: -------------------------------------------------------------------------------- 1 | import * as https from 'https'; 2 | import { ShopifyThemesResponse } from './shopify-api-models'; 3 | 4 | /** 5 | * Fetch the live theme ID from Shopify 6 | * 7 | * @param themekitEnvConfig String The themekit environment to get the live theme ID from 8 | * @return Promise Reason for abort or the live theme ID 9 | */ 10 | export function getLiveThemeId( 11 | storeHost: string, 12 | password: string 13 | ): Promise { 14 | return new Promise((resolve, reject) => { 15 | https.get( 16 | { 17 | hostname: storeHost, 18 | path: '/admin/themes.json', 19 | auth: `:${password}`, 20 | agent: false, 21 | headers: { 22 | 'X-Shopify-Access-Token': password, 23 | }, 24 | }, 25 | (res) => { 26 | let rawResponseBody = ''; 27 | 28 | res.on('data', (chunk) => (rawResponseBody += chunk)); 29 | 30 | res.on('end', () => { 31 | const responseBody: ShopifyThemesResponse = JSON.parse( 32 | rawResponseBody 33 | ); 34 | 35 | if (responseBody.errors) { 36 | reject( 37 | new Error( 38 | `API request to fetch main theme ID failed: \n${JSON.stringify( 39 | responseBody.errors, 40 | null, 41 | '\t' 42 | )}` 43 | ) 44 | ); 45 | return; 46 | } 47 | 48 | if (!Array.isArray(responseBody.themes)) { 49 | reject( 50 | new Error( 51 | `Shopify response for /admin/themes.json is not an array. ${JSON.stringify( 52 | responseBody, 53 | null, 54 | '\t' 55 | )}` 56 | ) 57 | ); 58 | return; 59 | } 60 | 61 | const liveTheme = responseBody.themes.find( 62 | (theme) => theme.role === 'main' 63 | ); 64 | 65 | if (!liveTheme) { 66 | reject( 67 | new Error( 68 | `No main theme in response. ${JSON.stringify( 69 | responseBody.themes, 70 | null, 71 | '\t' 72 | )}` 73 | ) 74 | ); 75 | return; 76 | } 77 | 78 | resolve(liveTheme.id); 79 | }); 80 | } 81 | ); 82 | }); 83 | } 84 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/shopify/shopify-theme-utils.ts: -------------------------------------------------------------------------------- 1 | import { joinPathFragments } from '@nrwl/devkit'; 2 | import * as glob from 'glob'; 3 | 4 | export const enum LiquidFileType { 5 | LAYOUT = 'layout', 6 | TEMPLATE = 'templates', 7 | SNIPPET = 'snippets', 8 | SECTION = 'sections', 9 | } 10 | 11 | export function getThemeLiquidFiles( 12 | fileBasename: string, 13 | liquidFileType: LiquidFileType, 14 | themeBaseDirectory: string 15 | ): string[] { 16 | const files = glob.sync( 17 | joinPathFragments( 18 | themeBaseDirectory, 19 | liquidFileType, 20 | '**', 21 | `${fileBasename}.liquid` 22 | ) 23 | ); 24 | return files; 25 | } 26 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/themekit/index.ts: -------------------------------------------------------------------------------- 1 | export * from './themekit-cli-utils'; 2 | export * from './themekit-config-utils'; 3 | export * from './themekit-validation-utils'; 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/themekit/themekit-cli-utils.ts: -------------------------------------------------------------------------------- 1 | import * as themekit from '@shopify/themekit'; 2 | 3 | export type ThemeKitCommand = 'version' | 'watch' | 'deploy' | 'open'; 4 | 5 | export type ThemeKitOptions = { 6 | cwd?: string; 7 | logLevel?: string; 8 | }; 9 | 10 | export type ThemeKitFlags = { 11 | password?: string; 12 | store?: string; 13 | themeid?: string; 14 | env?: string; 15 | noIgnore?: string; 16 | allowLive?: boolean; 17 | ignoredFile?: string; 18 | ignoredFiles?: string[]; 19 | notify?: string; 20 | nodelete?: boolean; 21 | files?: string[]; 22 | }; 23 | 24 | export type ThemekitRunResult = { success: boolean }; 25 | 26 | export function runThemekitCommand( 27 | command: ThemeKitCommand, 28 | flagObj: ThemeKitFlags = {}, 29 | options?: ThemeKitOptions 30 | ): Promise { 31 | return themekit.command(command, flagObj, options); 32 | } 33 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/themekit/themekit-config-utils.ts: -------------------------------------------------------------------------------- 1 | import { ExecutorContext } from '@nrwl/devkit'; 2 | import * as fs from 'fs'; 3 | import { load } from 'js-yaml'; 4 | import * as path from 'path'; 5 | import * as camelcaseKeys from 'camelcase-keys'; 6 | 7 | export interface ThemekitEnvironmentConfig { 8 | password: string; 9 | themeId: string; 10 | store: string; 11 | proxy: string; 12 | ignoreFiles: string[]; 13 | } 14 | 15 | export interface ThemekitConfig { 16 | [environment: string]: ThemekitEnvironmentConfig; 17 | } 18 | 19 | export async function getThemekitConfig( 20 | configPath: string, 21 | context: ExecutorContext 22 | ): Promise { 23 | const configAbsolutePath = path.join(context.root, configPath); 24 | 25 | if (!fs.existsSync(configAbsolutePath)) { 26 | throw new Error( 27 | `Can not find themekit config file at ${configAbsolutePath}` 28 | ); 29 | } 30 | 31 | let themekitConfig: ThemekitConfig = null; 32 | 33 | try { 34 | const configYaml = load(fs.readFileSync(configAbsolutePath, 'utf8'), { 35 | json: true, 36 | }) as ThemekitConfig; 37 | themekitConfig = camelcaseKeys(configYaml, { 38 | deep: true, 39 | }); 40 | } catch (error) { 41 | console.log(error); 42 | } 43 | return themekitConfig; 44 | } 45 | 46 | export async function getThemekitEnvironmentConfig( 47 | environment: string, 48 | configPath: string, 49 | context: ExecutorContext 50 | ): Promise { 51 | const themekitConfig = await getThemekitConfig(configPath, context); 52 | return themekitConfig[environment]; 53 | } 54 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/themekit/themekit-validation-utils.ts: -------------------------------------------------------------------------------- 1 | import { getLiveThemeId } from '../shopify'; 2 | import { ThemekitEnvironmentConfig } from './themekit-config-utils'; 3 | 4 | export async function isLiveTheme( 5 | themekitEnvConfig: ThemekitEnvironmentConfig 6 | ): Promise { 7 | const { store, password, themeId } = themekitEnvConfig; 8 | const liveThemeId = await getLiveThemeId(store, password); 9 | return themeId === liveThemeId.toString(); 10 | } 11 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/versions.ts: -------------------------------------------------------------------------------- 1 | export const autoprefixerVersion = '^10.1.0'; 2 | export const postcssCombineMediaQueryVersion = '^1.0.1'; 3 | export const documentReadyVersion = '^2.0.2'; 4 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/webpack-utils.ts: -------------------------------------------------------------------------------- 1 | import { Stats } from 'webpack'; 2 | import { BuildExecutorSchema } from '../executors/build/schema'; 3 | 4 | export function getAliases( 5 | options: BuildExecutorSchema 6 | ): { [key: string]: string } { 7 | return options.fileReplacements 8 | ? options.fileReplacements.reduce( 9 | (aliases, replacement) => ({ 10 | ...aliases, 11 | [replacement.replace]: replacement.with, 12 | }), 13 | {} 14 | ) 15 | : null; 16 | } 17 | 18 | export function getStatsConfig( 19 | options: BuildExecutorSchema 20 | ): Stats.ToStringOptions { 21 | return { 22 | hash: true, 23 | timings: false, 24 | cached: false, 25 | cachedAssets: false, 26 | modules: false, 27 | warnings: true, 28 | errors: true, 29 | colors: !options.verbose && !options.statsJson, 30 | chunks: !options.verbose, 31 | assets: !!options.verbose, 32 | chunkOrigins: !!options.verbose, 33 | chunkModules: !!options.verbose, 34 | children: !!options.verbose, 35 | reasons: !!options.verbose, 36 | version: !!options.verbose, 37 | errorDetails: !!options.verbose, 38 | moduleTrace: !!options.verbose, 39 | usedExports: !!options.verbose, 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/utils/workspace-utils.ts: -------------------------------------------------------------------------------- 1 | import { ExecutorContext, logger } from '@nrwl/devkit'; 2 | 3 | export async function getSourceRoot( 4 | context: ExecutorContext, 5 | projectName: string = null 6 | ): Promise { 7 | projectName = projectName ? projectName : context.projectName; 8 | const project = context.workspace.projects[projectName]; 9 | 10 | if (project.sourceRoot) { 11 | return project.sourceRoot as string; 12 | } else { 13 | const message = `${projectName} does not have a sourceRoot. Please define one.`; 14 | logger.error(message); 15 | throw new Error(message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/hmr/hmr-alamo-loader.ts: -------------------------------------------------------------------------------- 1 | function findEntry(mod) { 2 | if (mod.reasons.length > 0 && mod.reasons[0].module.resource) { 3 | return findEntry(mod.reasons[0].module); 4 | } 5 | return mod.resource; 6 | } 7 | 8 | /** 9 | * Adds a small script to flag unhandled HMR events. 10 | */ 11 | module.exports = function hmrAlamoLoader(content) { 12 | const entry = findEntry(this._module); 13 | 14 | if (this._module.resource === entry) { 15 | const alamo = ` 16 | // If we reached this module (the entry point), it means no one accepted the HRM. 17 | // Let's reload the page then. 18 | if (module.hot) { 19 | module.hot.accept(); 20 | // On first load, module.hot.data is undefined since it is not an update... 21 | // So if we do have a data object, it means we've been HMR'ed. 22 | if (module.hot.data) { 23 | window.__shopify__should_reload__ = true; 24 | } 25 | } 26 | `; 27 | 28 | return `${content}\n\n${alamo}`; 29 | } 30 | return content; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/hmr/hot-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* global __webpack_public_path__ __shopify_should_reload__ window */ 3 | // remove trailing slash from webpack public path 4 | // see https://github.com/glenjamin/webpack-hot-middleware/issues/154 5 | const tmpPublicPath = __webpack_public_path__; 6 | __webpack_public_path__ = __webpack_public_path__.replace(/\/$/, ''); 7 | const client = require('webpack-hot-middleware/client?dynamicPublicPath=true'); 8 | // and add the trailing slash again so we don't run into issue with webpack itself... 9 | __webpack_public_path__ = tmpPublicPath; 10 | 11 | // Entry points sets this to true if no modules accepted the HMR 12 | window.__shopify_should_reload__ = false; 13 | 14 | client.subscribe((event) => { 15 | if (event.action === 'shopify_upload_finished') { 16 | // Reload either if the serve force's our hand or if the entry point module 17 | if (event.force || window.__shopify_should_reload__) { 18 | setTimeout(() => window.location.reload(), 1300); 19 | } 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/partials/styles.config.ts: -------------------------------------------------------------------------------- 1 | import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; 2 | import { Configuration, Plugin } from 'webpack'; 3 | import { BuildExecutorSchema } from '../../../executors/build/schema'; 4 | import { getOutputHashFormat } from '../../utils'; 5 | 6 | function getExtraPlugins(options: BuildExecutorSchema) { 7 | const extraPlugins: Plugin[] = []; 8 | return extraPlugins; 9 | } 10 | 11 | export function getStylesWebpackPartialConfig( 12 | options: BuildExecutorSchema, 13 | chunksBaseName: string, 14 | isDevServer: boolean 15 | ): Configuration { 16 | const { postcssConfig, outputHashing } = options; 17 | 18 | const hashFormat = getOutputHashFormat(outputHashing); 19 | 20 | const webpackConfig: Configuration = { 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.s?css$/, 25 | exclude: /node_modules/, 26 | sideEffects: true, 27 | use: [ 28 | isDevServer 29 | ? require.resolve('style-loader') 30 | : MiniCssExtractPlugin.loader, 31 | require.resolve('css-loader'), 32 | { 33 | loader: require.resolve('postcss-loader'), 34 | options: { 35 | implementation: require('postcss'), 36 | postcssOptions: { 37 | config: postcssConfig, 38 | }, 39 | }, 40 | }, 41 | require.resolve('sass-loader'), 42 | ], 43 | }, 44 | ], 45 | }, 46 | plugins: [ 47 | new MiniCssExtractPlugin({ 48 | filename: `assets/[name]${hashFormat.script}.css`, 49 | chunkFilename: `assets/[name]${hashFormat.chunk}.css`, 50 | }), 51 | ...getExtraPlugins(options), 52 | ], 53 | }; 54 | 55 | return webpackConfig; 56 | } 57 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/templates/script-tags.html: -------------------------------------------------------------------------------- 1 | {% render 'webpack-public-path' %} 2 | <% for (var jsFile of htmlWebpackPlugin.files.js) { %> 3 | <% var fileName = jsFile.split('/').pop(); %> 4 | <% var src = `{{ '${fileName}' | asset_url }}` %> 5 | <% if (htmlWebpackPlugin.options.isDevServer) { %> 6 | <% src = jsFile %> 7 | <% } %> 8 | 9 | <% } %> 10 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/templates/style-tags.html: -------------------------------------------------------------------------------- 1 | <% for (var cssFile of htmlWebpackPlugin.files.css) { %> 2 | <% var fileName = cssFile.split('/').pop(); %> 3 | <% var src = `{{ '${fileName}' | asset_url }}` %> 4 | <% if (htmlWebpackPlugin.options.isDevServer) { %> 5 | <% src = cssFile %> 6 | <% } %> 7 | 8 | <% } %> 9 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/configs/templates/webpack-public-path.html: -------------------------------------------------------------------------------- 1 | <% if (htmlWebpackPlugin.options.isDevServer === true) { %> <% var anEntry = 2 | htmlWebpackPlugin.files.js[0]; %> 3 | 7 | <% } else { %> {% assign randomFile = 'randomFile.js' | asset_url %} {% assign 8 | cdnPath = randomFile | split: 'assets/randomFile.js' | first %} 9 | 12 | <% } %> 13 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/utils/hmr/hot-update-utils.ts: -------------------------------------------------------------------------------- 1 | export function isHotUpdateFile(filePath) { 2 | return ( 3 | /\.hot-update\.json$/.test(filePath) || 4 | /\.hot-update\.js(.map)?$/.test(filePath) 5 | ); 6 | } 7 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hmr/hot-update-utils'; 2 | export * from './output-utils'; 3 | -------------------------------------------------------------------------------- /packages/nx-shopify/src/webpack/utils/output-utils.ts: -------------------------------------------------------------------------------- 1 | export interface HashFormat { 2 | chunk: string; 3 | extract: string; 4 | file: string; 5 | script: string; 6 | } 7 | 8 | export function getOutputHashFormat(option: string, length = 20): HashFormat { 9 | const hashFormats: { [option: string]: HashFormat } = { 10 | none: { chunk: '', extract: '', file: '', script: '' }, 11 | media: { chunk: '', extract: '', file: `.[hash:${length}]`, script: '' }, 12 | bundles: { 13 | chunk: `.[chunkhash:${length}]`, 14 | extract: `.[contenthash:${length}]`, 15 | file: '', 16 | script: `.[hash:${length}]`, 17 | }, 18 | all: { 19 | chunk: `.[chunkhash:${length}]`, 20 | extract: `.[contenthash:${length}]`, 21 | file: `.[hash:${length}]`, 22 | script: `.[hash:${length}]`, 23 | }, 24 | }; 25 | return hashFormats[option] || hashFormats['none']; 26 | } 27 | -------------------------------------------------------------------------------- /packages/nx-shopify/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/nx-shopify/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["**/*.spec.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/nx-shopify/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.spec.tsx", 11 | "**/*.spec.js", 12 | "**/*.spec.jsx", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | // npx semantic-release --no-ci --branch=semantic-release-plus --extends=./packages/nx-shopify/release.config.js --debug 3 | const name = 'nx-shopify'; 4 | const srcRoot = `packages/${name}`; 5 | 6 | module.exports = { 7 | branches: [ 8 | '+([0-9])?(.{+([0-9]),x}).x', 9 | 'master', 10 | 'next', 11 | 'next-major', 12 | { name: 'rc', prerelease: true }, 13 | { name: 'beta', prerelease: true }, 14 | { name: 'alpha', prerelease: true }, 15 | ], 16 | pkgRoot: `dist/${srcRoot}`, 17 | tagFormat: 'v${version}', 18 | assets: [`CHANGELOG.md`], 19 | plugins: [ 20 | '@semantic-release/commit-analyzer', 21 | '@semantic-release/release-notes-generator', 22 | '@semantic-release/github', 23 | [ 24 | '@semantic-release/changelog', 25 | { 26 | changelogFile: `CHANGELOG.md`, 27 | }, 28 | ], 29 | '@semantic-release/npm', 30 | [ 31 | '@semantic-release/git', 32 | { 33 | message: 34 | `chore(release): ${name}` + 35 | '-v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', 36 | }, 37 | ], 38 | [ 39 | 'semantic-release-slack-bot', 40 | { 41 | notifyOnSuccess: true, 42 | notifyOnFail: true, 43 | onSuccessTemplate: { 44 | text: 45 | '\n\n:tada: A new version of `$package_name` has been released at <$repo_url|$repo_path>!\n\n' + 46 | '$release_notes\n\n' + 47 | 'The release is available on:\n' + 48 | '• \n' + 49 | '• \n\n' + 50 | 'Your bot', 51 | }, 52 | markdownReleaseNotes: true, 53 | branchesConfig: [ 54 | { 55 | pattern: 'alpha', 56 | notifyOnFail: false, 57 | }, 58 | ], 59 | }, 60 | ], 61 | ], 62 | }; 63 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trafilea/nx-shopify/1d192ee9b1c9c9d37597ec2c6e6e7f36bf8d9526/tools/generators/.gitkeep -------------------------------------------------------------------------------- /tools/scripts/commit-lint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { types, scopes } = require('../../.cz-config.js'); 4 | 5 | console.log('🐟🐟🐟 Validating git commit message 🐟🐟🐟'); 6 | const gitMessage = require('child_process') 7 | .execSync('git log -1 --no-merges') 8 | .toString() 9 | .trim(); 10 | 11 | const allowedTypes = types.map((type) => type.value); 12 | const allowedScopes = scopes.map((scope) => scope.name); 13 | 14 | const commitMsgRegex = `(${allowedTypes.join('|')})\\((${allowedScopes.join( 15 | '|' 16 | )})\\):\\s(([a-z0-9:\-\s])+)`; 17 | 18 | const matchCommit = new RegExp(commitMsgRegex, 'g').test(gitMessage); 19 | const matchRevert = /Revert/gi.test(gitMessage); 20 | const matchRelease = /Release/gi.test(gitMessage); 21 | const exitCode = +!(matchRelease || matchRevert || matchCommit); 22 | 23 | if (exitCode === 0) { 24 | console.log('Commit ACCEPTED 👌'); 25 | } else { 26 | console.log( 27 | '[Error]: Ho no! 😦 Your commit message: \n' + 28 | '-------------------------------------------------------------------\n' + 29 | gitMessage + 30 | '\n-------------------------------------------------------------------' + 31 | '\n\n 👉️ Does not follow the commit message convention specified in the CONTRIBUTING.MD file.' 32 | ); 33 | console.log('\ntype(scope): subject \n BLANK LINE \n body'); 34 | console.log('\n'); 35 | console.log(`possible types: ${allowedTypes.join('|')}`); 36 | console.log( 37 | `possible scopes: ${allowedScopes.join('|')} (if unsure use "core")` 38 | ); 39 | console.log( 40 | '\nEXAMPLE: \n' + 41 | 'feat(nx-shopify): add an option to generate a new theme section\n' 42 | ); 43 | console.log( 44 | `\nUse 'yarn commit' or 'npm run commit' to build commit messages\n` 45 | ); 46 | } 47 | process.exit(exitCode); 48 | -------------------------------------------------------------------------------- /tools/scripts/rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | nx build $1 --skip-nx-cache 3 | rm -rf tmp/nx-e2e/proj/node_modules/@trafilea/$1/src 4 | mkdir -p tmp/nx-e2e/proj/node_modules/@trafilea/$1/src 5 | cp -r dist/packages/$1/src/* tmp/nx-e2e/proj/node_modules/@trafilea/$1/src 6 | -------------------------------------------------------------------------------- /tools/scripts/release-env.example.sh: -------------------------------------------------------------------------------- 1 | export GIT_EMAIL=value 2 | export GIT_USERNAME=value 3 | export GIT_USER=value 4 | export GIT_PASS=value 5 | export GIT_AUTHOR_NAME=value 6 | export GIT_AUTHOR_EMAIL=value 7 | export GIT_COMMITTER_NAME=value 8 | export GIT_COMMITTER_EMAIL=value 9 | export GH_TOKEN=value 10 | export NPM_TOKEN=value 11 | export SLACK_WEBHOOK=value 12 | export SEMANTIC_RELEASE_PACKAGE=value 13 | -------------------------------------------------------------------------------- /tools/scripts/replace-themekit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -f tmp/nx-e2e/proj/node_modules/@shopify/themekit/bin/theme 3 | wget https://shopify-themekit.s3.amazonaws.com/v$1/linux-amd64/theme -O tmp/nx-e2e/proj/node_modules/@shopify/themekit/bin/theme 4 | chmod 755 tmp/nx-e2e/proj/node_modules/@shopify/themekit/bin/theme 5 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"] 9 | }, 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "typeRoots": ["node_modules/@types"], 14 | "lib": ["es2017", "dom"], 15 | "skipLibCheck": true, 16 | "skipDefaultLibCheck": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "trafilea/nx-shopify": ["packages/nx-shopify/src/index.ts"] 20 | } 21 | }, 22 | "exclude": ["node_modules", "tmp"] 23 | } 24 | --------------------------------------------------------------------------------