@softlimit/theme-envy 0.1.3-alpha → 0.1.5-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/build/functions/get-all.js +34 -15
  2. package/build/functions/index.js +0 -1
  3. package/build/functions/liquid/functions/list-dependencies.js +1 -1
  4. package/build/functions/liquid/functions/section-schema-inject.js +44 -4
  5. package/build/functions/parent-theme/index.js +77 -0
  6. package/build/functions/parent-theme/parent-theme-files.js +46 -0
  7. package/build/functions/webpack-plugins/retry-chunk-load-plugin.js +88 -0
  8. package/build/functions/webpack.js +24 -1
  9. package/build/index.js +3 -4
  10. package/build/requires/assets.js +2 -3
  11. package/build/requires/globals/index.js +0 -1
  12. package/build/requires/globals/prepare-install-hooks-schema.js +1 -2
  13. package/build/requires/globals/progress-bar.js +1 -2
  14. package/build/requires/globals/theme-require.js +11 -9
  15. package/build/requires/locales.js +13 -8
  16. package/build/requires/scripts/script-builders/elements.build.js +29 -21
  17. package/build/requires/styles/styles-builders/theme-envy.css.js +5 -1
  18. package/build/theme-envy.config.js +18 -7
  19. package/helpers/functions/parse-schema.js +20 -0
  20. package/helpers/functions/pull-json.js +1 -1
  21. package/helpers/index.js +1 -0
  22. package/index.js +1 -0
  23. package/init/functions/copy-starter-config-files/configs/postcss.config.js +7 -7
  24. package/init/functions/copy-starter-config-files/configs/tailwind.config.js +18 -4
  25. package/init/functions/copy-starter-config-files/configs/theme.config.js +1 -1
  26. package/package.json +10 -10
  27. package/build/functions/parent-theme-files.js +0 -25
  28. package/build/functions/tailwind.js +0 -31
  29. package/build/requires/globals/parent-theme.js +0 -28
  30. package/build/requires/styles/tailwind-base.css +0 -3
@@ -11,69 +11,87 @@
11
11
  */
12
12
  const path = require('path')
13
13
  const glob = require('glob')
14
- const parentThemeFiles = require('./parent-theme-files')
14
+ const parentThemeFiles = require('./parent-theme/parent-theme-files')
15
+
16
+ // ignore node_modules in globs
17
+ const globSync = (src, pattern) => glob.sync(path.resolve(src, pattern), {
18
+ ignore: {
19
+ ignored: p => {
20
+ // ignore node_modules in parent theme but not the parent theme itself (within node_modules)
21
+ if (ThemeEnvy.parentTheme) {
22
+ return p.fullpath().includes(path.resolve(ThemeEnvy.parentTheme.path, 'node_modules')) ? true : p.fullpath().includes('node_modules') && !p.fullpath().includes(ThemeEnvy.parentTheme.path)
23
+ }
24
+ return p.fullpath().includes('node_modules')
25
+ },
26
+ }
27
+ })
15
28
 
16
29
  const globs = {
17
30
  assets: {
18
31
  glob(src) {
19
- return glob.sync(path.resolve(src, '**/assets/**/*'))
32
+ return globSync(src, '**/assets/**/*')
20
33
  },
21
34
  },
22
35
  config: {
23
36
  glob(src) {
24
- return glob.sync(path.resolve(src, '**/config/**/*.js'))
37
+ return globSync(src, '**/config/**/*.js')
25
38
  },
26
39
  filter: file => path.basename(file) !== 'settings_schema.js',
27
40
  },
28
41
  criticalCSS: {
29
42
  glob(src) {
30
- return glob.sync(path.resolve(src, '**/critical.css'))
43
+ return globSync(src, '**/critical.css')
31
44
  },
32
45
  },
33
46
  elements: {
34
47
  glob(src) {
35
- return [...glob.sync(path.resolve(src, '**/elements/**/index.js')), ...glob.sync(path.resolve(src, '**/elements/*.js'))]
48
+ return [...globSync(src, '**/elements/**/index.js'), ...globSync(src, '**/elements/*.js')]
36
49
  }
37
50
  },
38
51
  features: {
39
52
  glob(src) {
40
- return glob.sync(path.resolve(src, 'theme-envy/features/**/index.js'))
53
+ return globSync(src, '**/features/**/index.js')
41
54
  },
42
55
  },
43
56
  installs: {
44
57
  glob(src) {
45
- return glob.sync(path.resolve(src, '**/install.js'))
58
+ return globSync(src, '**/install.js')
46
59
  },
47
60
  },
48
61
  liquid: {
49
62
  glob(src) {
50
- return glob.sync(path.resolve(src, '**/*.liquid'))
63
+ return globSync(src, '**/*.liquid')
51
64
  },
52
65
  filter: file => !file.includes('partials'),
53
66
  },
67
+ locales: {
68
+ glob(src) {
69
+ return globSync(src, '**/locales/**/*.json')
70
+ }
71
+ },
54
72
  partials: {
55
73
  glob(src) {
56
- return glob.sync(path.resolve(src, '**/partials/**/*.liquid'))
74
+ return globSync(src, '**/partials/**/*.liquid')
57
75
  },
58
76
  },
59
77
  schema: {
60
78
  glob(src) {
61
- return glob.sync(path.resolve(src, '**/schema/**/*.js'))
79
+ return globSync(src, '**/schema/**/*.js')
62
80
  },
63
81
  },
64
82
  sectionGroups: {
65
83
  glob(src) {
66
- return glob.sync(path.resolve(src, '**/sections/**/*.json'))
84
+ return globSync(src, '**/sections/**/*.json')
67
85
  },
68
86
  },
69
87
  snippets: {
70
88
  glob(src) {
71
- return glob.sync(path.resolve(src, '**/snippets/**/*.liquid'))
89
+ return globSync(src, '**/snippets/**/*.liquid')
72
90
  },
73
91
  },
74
92
  templates: {
75
93
  glob(src) {
76
- return glob.sync(path.resolve(src, '**/templates/**/*.json'))
94
+ return globSync(src, '**/templates/**/*.json')
77
95
  },
78
96
  },
79
97
  }
@@ -81,16 +99,17 @@ const globs = {
81
99
  module.exports = function(type) {
82
100
  function getFiles(src, only) {
83
101
  // src is either the themePath or the parentTheme
84
- // only is a list of directory names to filter against, used for parentTheme
102
+ // only is a list of directory paths to filter against, used for parentTheme
85
103
  let files = globs[type].glob(src)
86
104
  if (only) {
87
105
  files = files.filter(file => {
88
- return only.some(dir => file.indexOf(dir) > -1)
106
+ return only.some(dir => file.includes(`${dir}/`) || file.includes(`${dir}.js`))
89
107
  })
90
108
  }
91
109
  if (globs[type].filter) {
92
110
  files = files.filter(globs[type].filter)
93
111
  }
112
+
94
113
  return files
95
114
  }
96
115
  const files = getFiles(ThemeEnvy.themePath)
@@ -1,7 +1,6 @@
1
1
  module.exports = {
2
2
  getAll: require('./get-all'),
3
3
  liquid: require('./liquid'),
4
- tailwind: require('./tailwind'),
5
4
  themeEnvy: require('./theme-envy'),
6
5
  webpack: require('./webpack'),
7
6
  }
@@ -22,7 +22,7 @@ const listDependencies = ({ filePath, source }) => {
22
22
  const action = tag[2]
23
23
  const name = tag[3]
24
24
  if (action === 'partial') {
25
- const file = globbedPartials.filter(partial => partial.includes(`/${`${name}.liquid`}`))
25
+ const file = globbedPartials.filter(partial => path.basename(partial) === `${name}.liquid`)
26
26
  // if partialPath doesn't return anything, exit process and output error
27
27
  if (file.length === 0) {
28
28
  console.log(`\n${logSymbols.error} ${chalk.red.bold('Error:')}\n\n${chalk.red(`${name}.liquid`)} partial file not found, referenced in:\n${chalk.dim.underline(filePath)}\n\nTo resolve, confirm the partial file exists and that the file\nname reference in the {% partial %} tag matches the partial file.\n`)
@@ -1,21 +1,61 @@
1
1
  /**
2
2
  * @file Prebuild helper script that will inject the schema js file into the corresponding sections/*.liquid file
3
+ * also injects installs for blocks/section schema
3
4
  * @example
4
5
  * // include the schema in the section liquid file
5
6
  * {% schema 'schema-file.js' %}
6
7
  */
8
+ const path = require('path')
9
+ const { parseSchema } = require('#Helpers')
7
10
 
8
11
  module.exports = function({ source, filePath }) {
9
12
  if (!filePath.includes('sections')) return source
10
- const schema = source.match(/{% schema '(.*)' %}/g) || source.match(/{% schema "(.*)" %}/g)
11
- // if there are no schema tags with a filename string, return
12
- if (!schema) return source
13
+ // inject installs into inlined schema with {% schema %} {% endschema %} tags
14
+ const hasSchemaTag = source.match(/{% schema %}/g)
15
+ if (hasSchemaTag) return injectInstallsSchema({ source, filePath })
16
+ // inject schema from file into schema with {% schema 'filename.js' %} tags
17
+ const hasJsSchema = source.match(/{% schema '(.*)' %}/g) || source.match(/{% schema "(.*)" %}/g)
18
+ if (hasJsSchema) return injectJsSchema({ source, filePath, schema: hasJsSchema })
19
+ // if neither of the above...
20
+ return source
21
+ }
22
+
23
+ function injectJsSchema({ source, filePath, schema }) {
13
24
  // regexp for a quoted string within our schema match
14
25
  const schemaFile = schema[0].match(/'(.*)'/)[1] || schema[0].match(/"(.*)"/)[1]
15
26
  // load the file export
16
27
  const schemaSource = ThemeRequire(schemaFile, { loader: filePath })
28
+ // check for installs
29
+ const schemaWithInjections = checkInstalls({ schema: schemaSource, filePath })
17
30
  // replace the {% schema %} tag with the schema string and update asset
18
- return source.replace(schema[0], formatSchema(schemaSource))
31
+ return source.replace(schema[0], formatSchema(schemaWithInjections))
32
+ }
33
+
34
+ function injectInstallsSchema({ source, filePath }) {
35
+ // split our schema tag from the rest of the file
36
+ const { schema, schemaStart, schemaEnd } = parseSchema(source)
37
+ const schemaWithInjections = checkInstalls({ schema, filePath })
38
+ // replace everything between schemaStart and schemaEnd with the new schema
39
+ source = source.replace(source.substring(schemaStart, schemaEnd + String('{% endschema %}').length), formatSchema(schemaWithInjections))
40
+ return source
41
+ }
42
+
43
+ function checkInstalls({ schema, filePath }) {
44
+ // check our schema from install.js files and inject into schema
45
+ const sectionName = `${path.basename(path.dirname(filePath))}/${path.basename(filePath)}`
46
+ if (!ThemeEnvy.schema || !ThemeEnvy.schema[sectionName]) return schema
47
+
48
+ if (ThemeEnvy.schema[sectionName].settings) {
49
+ schema.settings = schema.settings || []
50
+ schema.settings = [...schema.settings, ...ThemeEnvy.schema[sectionName].settings]
51
+ }
52
+
53
+ if (ThemeEnvy.schema[sectionName].blocks) {
54
+ schema.blocks = schema.blocks || []
55
+ schema.blocks = [...schema.blocks, ...ThemeEnvy.schema[sectionName].blocks]
56
+ }
57
+
58
+ return schema
19
59
  }
20
60
 
21
61
  function formatSchema(schema) {
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @private
3
+ * @file Checks for a parent theme in node_modules or relative path and sets ThemeEnvy.parentTheme to the path
4
+ */
5
+
6
+ const fs = require('fs-extra')
7
+ const path = require('path');
8
+
9
+ (() => {
10
+ const ThemeConfigPath = path.resolve(process.cwd(), 'theme.config.js')
11
+ if (!fs.existsSync(ThemeConfigPath)) return
12
+ ThemeEnvy.childPreferred = ThemeEnvy.childPreferred || []
13
+
14
+ // look for parent theme in node_modules
15
+ const parentThemePath = ThemeEnvy.parentTheme?.path
16
+ if (!parentThemePath) {
17
+ removeParentThemeReference()
18
+ return
19
+ }
20
+ const parentThemePkg = fs.existsSync(path.resolve(process.cwd(), 'node_modules', parentThemePath))
21
+ ? path.resolve(process.cwd(), 'node_modules', parentThemePath)
22
+ : false
23
+ // look for parent theme in relative path
24
+ const parentThemeRelative = fs.existsSync(path.resolve(process.cwd(), parentThemePath))
25
+ ? path.resolve(process.cwd(), parentThemePath)
26
+ : false
27
+ // prefer node_modules over relative path
28
+ const parentTheme = parentThemePkg || parentThemeRelative
29
+
30
+ if (!parentTheme) {
31
+ removeParentThemeReference()
32
+ return
33
+ }
34
+ ThemeEnvy.parentTheme.path = parentTheme
35
+ // define elements and features arrays
36
+ ThemeEnvy.parentTheme.elements = listFeaturesOrElements({ type: 'elements' })
37
+ ThemeEnvy.parentTheme.features = listFeaturesOrElements({ type: 'features' })
38
+ })()
39
+
40
+ function removeParentThemeReference() {
41
+ delete ThemeEnvy.parentTheme
42
+ }
43
+
44
+ function listFeaturesOrElements({ type }) {
45
+ // get parentTheme config
46
+ const parentConfig = require(path.resolve(ThemeEnvy.parentTheme.path, 'parent.config.js'))
47
+ // get parentTheme theme-envy directory path
48
+ const parentThemeEnvyDir = path.resolve(ThemeEnvy.parentTheme.path, 'src/theme-envy')
49
+
50
+ const elementsOrFeatures = fs.readdirSync(path.resolve(parentThemeEnvyDir, type))
51
+ .filter(file => {
52
+ // remove items that are in the parent.config.js exclude array
53
+ if (!parentConfig[type]?.exclude) return true
54
+ return parentConfig[type].exclude.includes(path.parse(file).name) === false
55
+ })
56
+ .filter(file => {
57
+ // remove items that are in theme.config.js exclude array
58
+ if (!ThemeEnvy.parentTheme[type]?.exclude) return true
59
+ return ThemeEnvy.parentTheme[type]?.exclude.includes(path.parse(file).name) === false
60
+ })
61
+ .map(file => path.resolve(parentThemeEnvyDir, type, file).replace('.js', ''))
62
+
63
+ // add items that are in the include array of the child theme
64
+ if (ThemeEnvy.parentTheme[type]?.include) {
65
+ ThemeEnvy.parentTheme[type].include.forEach(item => {
66
+ if (!elementsOrFeatures.includes(item)) {
67
+ // check if the item exists in the parent theme
68
+ if (!fs.existsSync(path.resolve(parentThemeEnvyDir, type, item))) {
69
+ console.error(`The ${item} ${type} does not exist in the parent theme`)
70
+ return
71
+ }
72
+ elementsOrFeatures.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/theme-envy', type, item))
73
+ }
74
+ })
75
+ }
76
+ return elementsOrFeatures
77
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Get all files from the parent theme that are not in the child
3
+ * @private
4
+ * @param {function} func - function to get files with a glob, should return an array of file paths
5
+ * @param {array} childFiles - array of file paths from the child theme that we check against
6
+ * @returns {array} - array of file paths from the parent theme that are not in the child
7
+ */
8
+ const path = require('path')
9
+ const { directories } = require('#EnsureDirectories')
10
+ // sets resolved parent theme path
11
+ require('./index.js')
12
+
13
+ module.exports = (getFiles, childFiles, type) => {
14
+ const childRelative = childFiles.map(file => path.relative(process.cwd(), file))
15
+ // get all files from the parent theme, using only elements and features directories in parent theme
16
+ let only = [...ThemeEnvy.parentTheme.elements, ...ThemeEnvy.parentTheme.features]
17
+
18
+ if (type === 'elements') {
19
+ only = ThemeEnvy.parentTheme.elements
20
+ }
21
+ if (type === 'features') {
22
+ only = ThemeEnvy.parentTheme.features
23
+ }
24
+ if (type === 'schema') {
25
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/theme-envy/schema'))
26
+ }
27
+ if (type === 'liquid') {
28
+ only.push(...directories.map(dir => path.resolve(ThemeEnvy.parentTheme.path, 'src', dir)))
29
+ }
30
+ if (type === 'sectionGroups') {
31
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/sections'))
32
+ }
33
+ if (type === 'config') {
34
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/config'))
35
+ }
36
+ if (type === 'locales') {
37
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/locales'))
38
+ }
39
+ if (type === 'templates') {
40
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/templates'))
41
+ }
42
+ if (type === 'criticalCSS') {
43
+ only.push(path.resolve(ThemeEnvy.parentTheme.path, 'src/styles'))
44
+ }
45
+ return getFiles(ThemeEnvy.parentTheme.path, only).filter(file => !childRelative.includes(path.relative(ThemeEnvy.parentTheme.path, file)))
46
+ }
@@ -0,0 +1,88 @@
1
+ const prettier = require('prettier')
2
+ const { RuntimeGlobals } = require('webpack')
3
+
4
+ const pluginName = 'RetryChunkLoadPlugin'
5
+
6
+ class RetryChunkLoadPlugin {
7
+ constructor(options = {}) {
8
+ this.options = Object.assign({}, options)
9
+ }
10
+
11
+ apply(compiler) {
12
+ compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
13
+ const { mainTemplate, runtimeTemplate } = compilation
14
+ const maxRetryValueFromOptions = Number(this.options.maxRetries)
15
+ const maxRetries =
16
+ Number.isInteger(maxRetryValueFromOptions) &&
17
+ maxRetryValueFromOptions > 0
18
+ ? maxRetryValueFromOptions
19
+ : 1
20
+ // const getCacheBustString = () =>
21
+ // this.options.cacheBust
22
+ // ? `
23
+ // (${this.options.cacheBust})();
24
+ // `
25
+ // : '"cache-bust=true"'
26
+ mainTemplate.hooks.localVars.tap(
27
+ { name: pluginName, stage: 1 },
28
+ (source, chunk) => {
29
+ const currentChunkName = chunk.name
30
+ const addRetryCode =
31
+ !this.options.chunks ||
32
+ this.options.chunks.includes(currentChunkName)
33
+ if (!addRetryCode) return source
34
+ const script = runtimeTemplate.iife(
35
+ '',
36
+ `
37
+ if(typeof ${RuntimeGlobals.require} !== "undefined") {
38
+ var oldGetScript = ${RuntimeGlobals.getChunkScriptFilename};
39
+ var oldLoadScript = ${RuntimeGlobals.ensureChunk};
40
+ var queryMap = new Map();
41
+ var countMap = new Map();
42
+ ${RuntimeGlobals.getChunkScriptFilename} = function(chunkId){
43
+ var result = oldGetScript(chunkId);
44
+ return result + (queryMap.has(chunkId) ? '?' + queryMap.get(chunkId) : '');
45
+ };
46
+ ${RuntimeGlobals.ensureChunk} = function(chunkId){
47
+ var result = oldLoadScript(chunkId);
48
+ return result.catch(function(error){
49
+ var retries = countMap.has(chunkId) ? countMap.get(chunkId) : ${maxRetries};
50
+ if (retries < 1) {
51
+ var realSrc = oldGetScript(chunkId);
52
+ error.message = 'Loading chunk ' + chunkId + ' failed after ${maxRetries} retries.\\n(' + realSrc + ')';
53
+ error.request = realSrc;${
54
+ this.options.lastResortScript
55
+ ? this.options.lastResortScript
56
+ : ''
57
+ }
58
+ throw error;
59
+ }
60
+ return new Promise(function (resolve) {
61
+ setTimeout(function () {
62
+ var retryAttempt = ${maxRetries} - retries + 1;
63
+ var retryAttemptString = '&retry-attempt=' + retryAttempt;
64
+ const cacheBust = Date.now();
65
+ queryMap.set(chunkId, cacheBust);
66
+ countMap.set(chunkId, retries - 1);
67
+ resolve(${RuntimeGlobals.ensureChunk}(chunkId));
68
+ }, ${this.options.retryDelay || this.options.timeout || 0})
69
+ })
70
+ });
71
+ };
72
+ }`
73
+ )
74
+ return (
75
+ source +
76
+ prettier.format(script, {
77
+ trailingComma: 'es5',
78
+ singleQuote: true,
79
+ parser: 'babel'
80
+ })
81
+ )
82
+ }
83
+ )
84
+ })
85
+ }
86
+ }
87
+
88
+ module.exports.RetryChunkLoadPlugin = RetryChunkLoadPlugin
@@ -8,6 +8,7 @@
8
8
  * @returns {Promise}
9
9
  */
10
10
 
11
+ const path = require('path')
11
12
  const webpack = require('webpack')
12
13
  const getAll = require('./get-all')
13
14
 
@@ -25,12 +26,34 @@ module.exports = function({ mode, opts }) {
25
26
  webpackConfig.watch = watch
26
27
  // merge our theme config named entries into webackConfig.entry
27
28
  webpackConfig.entry = { ...webpackConfig.entry, ...ThemeEnvy.entry }
29
+ // merge our theme config resolve aliases into webpackConfig.resolve.alias
30
+ if (ThemeEnvy.resolve?.alias) webpackConfig.resolve.alias = { ...webpackConfig.resolve.alias, ...ThemeEnvy.resolve.alias }
28
31
 
32
+ if (ThemeEnvy?.tailwind !== false) {
33
+ // if tailwind is enabled, we need to add our critical css to the entry list
34
+ webpackConfig.entry['theme-envy.critical'] = [`${ThemeEnvy.paths.build}/requires/styles/theme-envy.css`]
35
+ }
29
36
  if (ThemeEnvy?.tailwind === false && getAll('criticalCSS').length > 0) {
30
37
  // if tailwind is disabled, we need to add our critical css to the entry list
31
- webpackConfig.entry['theme-envy.critical'] = `${ThemeEnvy.paths.build}/requires/styles/theme-envy.css`
38
+ webpackConfig.entry['theme-envy.critical'] = [`${ThemeEnvy.paths.build}/requires/styles/theme-envy.css`]
32
39
  }
33
40
 
41
+ // check for Aliases and Entries in parent theme parent.config.js and merge them with our own
42
+ if (ThemeEnvy.parentTheme) {
43
+ const parentThemeConfig = require(path.resolve(ThemeEnvy.parentTheme.path, 'parent.config.js'))
44
+ // merge parent theme aliases into webpackConfig.resolve.alias
45
+ if (parentThemeConfig.resolve?.alias) webpackConfig.resolve.alias = { ...webpackConfig.resolve.alias, ...parentThemeConfig.resolve.alias }
46
+ // iterate over parent theme entries and add them to webpackConfig.entry, merging with our own into an array if necessary
47
+ if (parentThemeConfig.entry) {
48
+ for (const [key, value] of Object.entries(parentThemeConfig.entry)) {
49
+ if (webpackConfig.entry[key]) {
50
+ webpackConfig.entry[key] = [...webpackConfig.entry[key], ...value]
51
+ } else {
52
+ webpackConfig.entry[key] = [...value]
53
+ }
54
+ }
55
+ }
56
+ }
34
57
  webpack(webpackConfig, (err, stats) => {
35
58
  if (err || stats.hasErrors()) {
36
59
  console.log(stats, err)
package/build/index.js CHANGED
@@ -15,14 +15,15 @@
15
15
  const path = require('path')
16
16
  const chalk = require('chalk')
17
17
  const emoji = require('node-emoji')
18
- const { themeEnvy, webpack, tailwind } = require('#Build/functions')
18
+ const { themeEnvy, webpack } = require('#Build/functions')
19
19
  const { distClean } = require('#Helpers')
20
20
 
21
21
  module.exports = async function(env, opts = {}) {
22
22
  const mode = env || 'production'
23
+ process.env.mode = mode
23
24
 
24
25
  // empty dist folder for a clean build, do not log the clean message
25
- distClean({ quiet: true })
26
+ if (opts.clean || !opts.watch) distClean({ quiet: true })
26
27
 
27
28
  // our pretty build message
28
29
  const relativeDistPath = path.relative(process.cwd(), ThemeEnvy.outputPath)
@@ -37,8 +38,6 @@ module.exports = async function(env, opts = {}) {
37
38
 
38
39
  await themeEnvy({ mode, opts })
39
40
 
40
- if (ThemeEnvy?.tailwind !== false) await tailwind({ mode, opts })
41
-
42
41
  await webpack({ mode, opts })
43
42
 
44
43
  ThemeEnvy.events.emit('build:complete')
@@ -4,9 +4,8 @@
4
4
 
5
5
  const fs = require('fs-extra')
6
6
  const path = require('path')
7
- const glob = require('glob')
8
-
9
- const assets = glob.sync(path.resolve(ThemeEnvy.themePath, '**/assets/**/*.*'))
7
+ const { getAll } = require('#Build/functions')
8
+ const assets = getAll('assets')
10
9
 
11
10
  // if dist/assets doesn't exist create it
12
11
  fs.ensureDirSync(path.resolve(ThemeEnvy.outputPath, 'assets'))
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  require('./progress-bar')
7
- require('./parent-theme')
8
7
  require('./theme-require')
9
8
  require('./prepare-install-hooks-schema')
10
9
  ThemeEnvy.progress.increment('globals')
@@ -43,7 +43,6 @@ const path = require('path');
43
43
  }
44
44
  })
45
45
 
46
- // TODO: LOOK INTO THIS
47
46
  schema.forEach(entry => {
48
47
  const file = `${entry.file}.liquid`
49
48
  ThemeEnvy.schema[file] = ThemeEnvy.schema[file] || {
@@ -53,6 +52,6 @@ const path = require('path');
53
52
  // add the schema to the destination, process entry.content for softlimit partials
54
53
  // target is either 'settings' or 'blocks'
55
54
  const target = entry.target.split('.')[1]
56
- ThemeEnvy.schema[file][target].push(entry.content)
55
+ ThemeEnvy.schema[file][target] = [...ThemeEnvy.schema[file][target], ...entry.content]
57
56
  })
58
57
  })()
@@ -16,10 +16,9 @@ const colors = require('ansi-colors');
16
16
  failedHookInstalls: 1,
17
17
  globals: 1,
18
18
  liquid: getAll('liquid').length,
19
- locales: 1,
19
+ locales: getAll('locales').length,
20
20
  requires: 7,
21
21
  sectionGroups: 1,
22
- tailwind: ThemeEnvy?.tailwind !== false ? 1 : 0,
23
22
  templates: getAll('templates').length,
24
23
  webpack: 1,
25
24
  }
@@ -33,7 +33,9 @@ ThemeEnvy.events.on('watch:start', () => {
33
33
  })
34
34
 
35
35
  const ThemeRequire = (file, options) => {
36
- // check for file in our pre-globbed arrays
36
+ // assume files are javascript if no extension given
37
+ if (!path.extname(file)) file = `${file}.js`
38
+
37
39
  const ref = getFile(file)
38
40
 
39
41
  if (ref.length === 0) {
@@ -87,10 +89,10 @@ const ThemeRequire = (file, options) => {
87
89
  content = schemaExtend(content, options.extend)
88
90
  }
89
91
  if (options?.loop) {
90
- content = schemaLoop(file, content, options.loop)
92
+ content = schemaLoop(content, options.loop)
91
93
  }
92
94
  if (options?.suffix) {
93
- content = schemaSuffix(file, content, options.suffix)
95
+ content = schemaSuffix(content, options.suffix)
94
96
  }
95
97
 
96
98
  if (options?.loader) {
@@ -101,7 +103,7 @@ const ThemeRequire = (file, options) => {
101
103
  return content
102
104
  }
103
105
 
104
- function schemaDelete(file, src, del) {
106
+ function schemaDelete(src, del) {
105
107
  const replaceWith = src.filter(entry => {
106
108
  if (entry.settings) {
107
109
  entry.settings = schemaDelete(entry.settings, del)
@@ -130,7 +132,7 @@ function schemaExtend(src, exts) {
130
132
  return replaceWith
131
133
  }
132
134
 
133
- function schemaLoop(file, src, loop) {
135
+ function schemaLoop(src, loop) {
134
136
  const replaceWith = []
135
137
  for (let i = 1; i < (loop + 1); i++) {
136
138
  const srcCopy = parseJson(src)
@@ -145,7 +147,7 @@ function schemaLoop(file, src, loop) {
145
147
  return replaceWith
146
148
  }
147
149
 
148
- function schemaSuffix(file, src, suffix) {
150
+ function schemaSuffix(src, suffix) {
149
151
  const replaceWith = parseJson(src)
150
152
  replaceWith.map(entry => {
151
153
  if (entry.id) entry.id = `${entry.id}_${suffix}`
@@ -165,8 +167,8 @@ function getFile(file) {
165
167
  return getSchemaFile(file)
166
168
  } else {
167
169
  const res = glob.sync(path.resolve(ThemeEnvy.themePath, `**/${file}`))
168
- if (ThemeEnvy.parentTheme && res.length === 0) {
169
- res.push(...glob.sync(path.resolve(ThemeEnvy.parentTheme, `**/${file}`)))
170
+ if (ThemeEnvy.parentTheme.path && res.length === 0) {
171
+ res.push(...glob.sync(path.resolve(ThemeEnvy.parentTheme.path, `**/${file}`)))
170
172
  }
171
173
  return res
172
174
  }
@@ -176,7 +178,7 @@ function getFile(file) {
176
178
  @param src [object] - the file contents to be extended
177
179
  @param schemaRef [string] - source schema file name being extended
178
180
  */
179
- function parseJson(src, schemaRef) {
181
+ function parseJson(src) {
180
182
  try {
181
183
  return JSON.parse(JSON.stringify(src))
182
184
  } catch (error) {
@@ -3,14 +3,19 @@
3
3
  */
4
4
  const fs = require('fs-extra')
5
5
  const path = require('path')
6
+ const { getAll } = require('#Build/functions')
6
7
 
7
- // if dist/locales does not exist, create it
8
+ const locales = getAll('locales')
9
+
10
+ // if dist/locales doesn't exist create it
8
11
  fs.ensureDirSync(path.resolve(ThemeEnvy.outputPath, 'locales'))
9
12
 
10
- try {
11
- fs.copySync(path.resolve(ThemeEnvy.themePath, 'locales'), path.resolve(ThemeEnvy.outputPath, 'locales'))
12
- // update progress bar
13
- ThemeEnvy.progress.increment('locales')
14
- } catch (err) {
15
- console.error(err)
16
- }
13
+ locales.forEach(locale => {
14
+ try {
15
+ fs.copySync(locale, path.resolve(ThemeEnvy.outputPath, 'locales', path.basename(locale)))
16
+ // update progress bar
17
+ ThemeEnvy.progress.increment('locales', 1)
18
+ } catch (err) {
19
+ console.error(err)
20
+ }
21
+ })
@@ -7,38 +7,46 @@ const path = require('path')
7
7
  const fs = require('fs-extra')
8
8
  const { getAll } = require('#Build/functions')
9
9
  const elements = getAll('elements').map(file => {
10
- const name = path.basename === 'index.js' ? path.basename(path.dirname(file)) : path.basename(file, '.js')
10
+ const name = path.basename(file) === 'index.js' ? path.basename(path.dirname(file)) : path.basename(file, '.js')
11
11
  return `'${name}': () => import(/* webpackChunkName: "${name}" */ '${file}')`
12
12
  })
13
13
 
14
14
  const markup = elements.length
15
- ? `const elements = {${elements.join(',\n')}}
15
+ ? `const elements = {
16
+ ${elements.join(',\n ')}}
16
17
  // check all elements for presence in the Document and load if they are there
17
- Object.entries(elements).forEach(elm => {
18
- const domElm = document.querySelector(elm[0])
19
- if (domElm) {
20
- if (domElm.getAttribute('loading') === 'lazy') {
21
- const observer = new IntersectionObserver((entries, observer) => {
22
- entries.forEach(entry => {
23
- if (entry.isIntersecting) {
24
- loadElement(elm)
25
- domElm.setAttribute('loading', 'loaded')
26
- observer.disconnect()
27
- }
28
- })
29
- }, { rootMargin: '0px 0px 500px 0px', threshold: 0 })
30
- observer.observe(domElm)
31
- return
32
- }
33
- loadElement(elm)
34
- }
35
- })
18
+ function dynamicElements() {
19
+ Object.entries(elements).forEach(elm => {
20
+ const domElm = document.querySelector(elm[0])
21
+ if (domElm) {
22
+ if (domElm.getAttribute('loading') === 'lazy') {
23
+ const observer = new IntersectionObserver((entries, observer) => {
24
+ entries.forEach(entry => {
25
+ if (entry.isIntersecting) {
26
+ loadElement(elm)
27
+ domElm.setAttribute('loading', 'loaded')
28
+ observer.disconnect()
29
+ }
30
+ })
31
+ }, { rootMargin: '0px 0px 500px 0px', threshold: 0 })
32
+ observer.observe(domElm)
33
+ return
34
+ }
35
+ loadElement(elm)
36
+ }
37
+ })
38
+ }
39
+ dynamicElements()
36
40
  function loadElement(elm) {
37
41
  // load the element
38
42
  elm[1]()
39
43
  // remove from Object so we don't need to check again
40
44
  delete elements[elm[0]]
41
45
  }
46
+ // eslint-disable-next-line no-undef
47
+ if (Shopify.designMode) {
48
+ document.addEventListener('shopify:section:load', dynamicElements)
49
+ }
42
50
  `
43
51
  : ''
44
52
  fs.writeFileSync(path.resolve(__dirname, '../elements.js'), markup, 'utf8')
@@ -4,7 +4,11 @@ const getAll = require('#Build/functions/get-all.js')
4
4
 
5
5
  const criticalCSS = getAll('criticalCSS')
6
6
 
7
- const markup = `${ThemeEnvy.tailwind !== false ? "@import './tailwind-base.css'" : ''};
7
+ const markup = `${ThemeEnvy.tailwind !== false
8
+ ? `@import 'tailwindcss/base';
9
+ @import 'tailwindcss/components';
10
+ @import 'tailwindcss/utilities';`
11
+ : ''}
8
12
  ${criticalCSS.map(file => `@import '${file}';`).join('\n')}
9
13
  `
10
14
 
@@ -1,12 +1,14 @@
1
+ const path = require('path')
2
+
3
+ const { EsbuildPlugin } = require('esbuild-loader')
4
+ const { RetryChunkLoadPlugin } = require('./functions/webpack-plugins/retry-chunk-load-plugin')
1
5
  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
2
- const TerserPlugin = require('terser-webpack-plugin')
3
6
  const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts')
4
- const { ESBuildMinifyPlugin } = require('esbuild-loader')
5
- const path = require('path')
7
+ const TerserPlugin = require('terser-webpack-plugin')
6
8
 
7
9
  module.exports = {
8
10
  entry: {
9
- 'theme-envy': path.resolve(__dirname, 'requires/scripts/theme-envy.js'),
11
+ 'theme-envy': [path.resolve(__dirname, 'requires/scripts/theme-envy.js')],
10
12
  },
11
13
  output: {
12
14
  path: path.resolve(ThemeEnvy.outputPath, 'assets'),
@@ -25,6 +27,7 @@ module.exports = {
25
27
  return '[name].js?h=[contenthash:5]'
26
28
  }
27
29
  },
30
+ devtool: false,
28
31
  module: {
29
32
  rules: [
30
33
  {
@@ -44,7 +47,7 @@ module.exports = {
44
47
  sideEffects: false,
45
48
  minimizer: [
46
49
  (process.env.mode === 'production')
47
- ? new ESBuildMinifyPlugin({
50
+ ? new EsbuildPlugin({
48
51
  target: 'es2015', // Syntax to compile to (see options below for possible values)
49
52
  })
50
53
  : new TerserPlugin({
@@ -56,16 +59,24 @@ module.exports = {
56
59
  alias: {
57
60
  Build: ThemeEnvy.paths.build,
58
61
  Helpers: ThemeEnvy.paths.helpers,
59
- Elements: path.resolve(ThemeEnvy.themePath, 'theme-envy/elements/'),
60
- Features: path.resolve(ThemeEnvy.themePath, 'theme-envy/features/'),
61
62
  Root: path.resolve(process.cwd()),
62
63
  Scripts: path.resolve(ThemeEnvy.themePath, 'scripts/'),
63
64
  },
65
+ modules: ['node_modules'],
66
+ },
67
+ resolveLoader: {
68
+ modules: ['node_modules'],
64
69
  },
65
70
  plugins: [
66
71
  new RemoveEmptyScriptsPlugin(),
67
72
  new MiniCssExtractPlugin({
68
73
  filename: '[name].css?h=[chunkhash:5]',
69
74
  }),
75
+ new RetryChunkLoadPlugin({
76
+ // optional value to set the amount of time in milliseconds before trying to load the chunk again. Default is 0
77
+ retryDelay: 0,
78
+ // optional value to set the maximum number of retries to load the chunk. Default is 1
79
+ maxRetries: 3
80
+ }),
70
81
  ]
71
82
  }
@@ -0,0 +1,20 @@
1
+ const strings = {
2
+ schemaStart: '{% schema %}',
3
+ schemaEnd: '{% endschema %}',
4
+ }
5
+
6
+ module.exports = function(source, file) {
7
+ const schemaStart = source.indexOf(strings.schemaStart)
8
+ const schemaEnd = source.indexOf(strings.schemaEnd)
9
+ if (schemaStart === -1 || schemaEnd === -1) return source
10
+ try {
11
+ return {
12
+ schema: JSON.parse(source.slice(schemaStart + strings.schemaStart.length, schemaEnd)),
13
+ schemaStart,
14
+ schemaEnd
15
+ }
16
+ } catch (error) {
17
+ console.error(file, error)
18
+ process.exit()
19
+ }
20
+ }
@@ -12,7 +12,7 @@ const { spawn } = require('child_process')
12
12
 
13
13
  module.exports = function() {
14
14
  const relativeDistPath = path.relative(process.cwd(), ThemeEnvy.outputPath)
15
- const themePull = ['theme', 'pull', `--store=${ThemeEnvy.store}`, `--path=${relativeDistPath}`, '--only=templates/*.json,config/settings_data.json,sections/*.json']
15
+ const themePull = ['theme', 'pull', `--store=${ThemeEnvy.store}`, `--path=${relativeDistPath}`]
16
16
  const shopify = spawn('shopify', themePull, { cwd: ThemeEnvy.outputPath, stdio: 'inherit' })
17
17
 
18
18
  shopify.on('exit', function() {
package/helpers/index.js CHANGED
@@ -5,6 +5,7 @@ module.exports = {
5
5
  globalThemeEnvy: require('./functions/global-theme-envy.js'),
6
6
  liquidPrettify: require('./functions/liquid-prettify.js'),
7
7
  liquidTree: require('./functions/liquid-tree'),
8
+ parseSchema: require('./functions/parse-schema.js'),
8
9
  pullJson: require('./functions/pull-json.js'),
9
10
  scaffoldNew: require('./functions/scaffold-new'),
10
11
  }
package/index.js CHANGED
@@ -116,6 +116,7 @@ program
116
116
  .description('Build Shopify theme')
117
117
  .usage('[development|production] -w|--watch')
118
118
  .addArgument(new commander.Argument('[env]', 'Specify the build environment to run').choices(['development', 'production']))
119
+ .option('-c, --clean', 'Clean output directory before building')
119
120
  .option('-w, --watch', 'Watch for changed files and update dist, serve with Shopify CLI')
120
121
  .option('-v, --verbose', 'Show Tailwind and Webpack in output')
121
122
  .action((env, options, command) => {
@@ -1,9 +1,9 @@
1
1
  module.exports = {
2
- plugins: [
3
- require('postcss-import'),
4
- require('tailwindcss/nesting'),
5
- require('tailwindcss'),
6
- require('autoprefixer'),
7
- require('cssnano')
8
- ]
2
+ plugins: {
3
+ 'postcss-import': {},
4
+ 'tailwindcss/nesting': {},
5
+ tailwindcss: {},
6
+ autoprefixer: {},
7
+ cssnano: {}
8
+ }
9
9
  }
@@ -2,15 +2,29 @@
2
2
  * @private
3
3
  * @type {import('tailwindcss').Config}
4
4
  */
5
- const theme = require('./theme.config.js')
6
5
  const path = require('path')
7
6
  const ThemeEnvy = require('./theme.config.js')
8
7
 
9
- module.exports = {
10
- content: [path.resolve(ThemeEnvy.themePath, '**/*.{liquid,js}')],
8
+ const config = {
9
+ content: [
10
+ path.resolve(ThemeEnvy.themePath, '**/*.{liquid,js}'),
11
+ ],
11
12
  theme: {
12
13
  extend: {},
13
14
  },
14
- screens: theme.breakpoints,
15
+ screens: ThemeEnvy.breakpoints,
15
16
  plugins: [],
16
17
  }
18
+
19
+ // merge parentTheme tailwind config if it exists
20
+ if (ThemeEnvy.parentTheme?.path) {
21
+ const parentTailwind = require(path.join(path.dirname(require.resolve(ThemeEnvy.parentTheme.path)), 'tailwind.config.js'))
22
+ // deep merge parentTheme tailwind config with child theme tailwind config
23
+ if (parentTailwind) {
24
+ config.theme.extend = Object.assign(config.theme.extend, parentTailwind.theme.extend)
25
+ config.plugins = config.plugins.concat(parentTailwind.plugins)
26
+ config.content = config.content.concat(parentTailwind.content)
27
+ }
28
+ }
29
+
30
+ module.exports = config
@@ -1,6 +1,6 @@
1
1
  module.exports = {
2
2
  entry: {
3
- // main: './src/scripts/main.js',
3
+ // main: ['./src/scripts/main.js'],
4
4
  },
5
5
  store: 'my-store.myshopify.com',
6
6
  themePath: 'src',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softlimit/theme-envy",
3
- "version": "0.1.3-alpha",
3
+ "version": "0.1.5-alpha",
4
4
  "description": "Softlimit Shopify Theme Development Environment",
5
5
  "bin": {
6
6
  "theme-envy": "./index.js"
@@ -28,7 +28,6 @@
28
28
  "#Init/functions": "./init/functions/index.js",
29
29
  "#Init/functions/*": "./init/functions/*",
30
30
  "#LogSymbols": "./helpers/functions/log-symbols.js",
31
- "#ParentTheme": "./parent-theme/index.js",
32
31
  "#Root/*": "./*"
33
32
  },
34
33
  "repository": {
@@ -52,7 +51,7 @@
52
51
  "dependencies": {
53
52
  "@shopify/prettier-plugin-liquid": "^1.0.6",
54
53
  "ansi-colors": "^4.1.3",
55
- "autoprefixer": "^10.4.13",
54
+ "autoprefixer": "^10.4.14",
56
55
  "chalk": "^4.1.2",
57
56
  "chokidar": "^3.5.3",
58
57
  "cli-progress": "^3.12.0",
@@ -60,8 +59,13 @@
60
59
  "css-loader": "^6.7.3",
61
60
  "cssnano": "^5.1.15",
62
61
  "esbuild-loader": "^3.0.1",
62
+ "eslint": "^8.34.0",
63
+ "eslint-config-standard": "^17.0.0",
64
+ "eslint-plugin-import": "^2.27.5",
65
+ "eslint-plugin-n": "^15.6.1",
66
+ "eslint-plugin-promise": "^6.1.1",
63
67
  "fs-extra": "^11.1.0",
64
- "glob": "^8.1.0",
68
+ "glob": "^10.2.1",
65
69
  "mini-css-extract-plugin": "^2.7.2",
66
70
  "node-emoji": "^1.11.0",
67
71
  "path": "^0.12.7",
@@ -71,18 +75,14 @@
71
75
  "promptly": "^3.2.0",
72
76
  "simple-git": "^3.17.0",
73
77
  "stmux": "^1.8.5",
74
- "tailwindcss": "^3.2.7",
78
+ "tailwindcss": "^3.3.1",
75
79
  "terser-webpack-plugin": "^5.3.6",
76
80
  "webpack": "^5.77.0",
77
81
  "webpack-cli": "^5.0.1",
78
82
  "webpack-remove-empty-scripts": "^1.0.1"
79
83
  },
80
84
  "devDependencies": {
81
- "eslint": "^8.34.0",
82
- "eslint-config-standard": "^17.0.0",
83
- "eslint-plugin-import": "^2.27.5",
84
- "eslint-plugin-n": "^15.6.1",
85
- "eslint-plugin-promise": "^6.1.1",
85
+ "caller": "^1.1.0",
86
86
  "jsdoc": "^4.0.2"
87
87
  }
88
88
  }
@@ -1,25 +0,0 @@
1
- /**
2
- * Get all files from the parent theme that are not in the child
3
- * @private
4
- * @param {function} func - function to get files with a glob, should return an array of file paths
5
- * @param {array} childFiles - array of file paths from the child theme that we check against
6
- * @returns {array} - array of file paths from the parent theme that are not in the child
7
- */
8
- const path = require('path')
9
- const { directories } = require('#EnsureDirectories')
10
-
11
- module.exports = (func, childFiles, type) => {
12
- const childRelative = childFiles.map(file => path.relative(ThemeEnvy.themePath, file))
13
- // get all files from the parent theme, using only directories listed in ThemeConfig
14
- const only = [...ThemeEnvy.parentTheme.elements, ...ThemeEnvy.parentTheme.features]
15
- if (type === 'schema') {
16
- only.push('schema')
17
- }
18
- if (type === 'liquid') {
19
- only.push(...directories.map(dir => path.resolve(ThemeEnvy.parentTheme, dir)))
20
- }
21
- if (type === 'sectionGroups') {
22
- only.push(path.resolve(ThemeEnvy.parentTheme, 'sections'))
23
- }
24
- return func(ThemeEnvy.parentTheme, only).filter(file => !childRelative.includes(path.relative(ThemeEnvy.parentTheme, file)))
25
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * @private
3
- * @file Runs Tailwind using the Tailwind CLI during build
4
- * @see https://tailwindcss.com/docs/installation#using-tailwind-cli
5
- */
6
- const { spawn } = require('child_process')
7
- const path = require('path')
8
-
9
- module.exports = function({ mode, opts }) {
10
- return new Promise((resolve, reject) => {
11
- const watch = opts.watch || false
12
- const verbose = opts.verbose || false
13
-
14
- // run tailwind
15
- const tailwindCss = path.resolve(__dirname, '../requires/styles/theme-envy.css')
16
- const tailwindOpts = ['tailwindcss', 'build', '-i', tailwindCss, '-o', `${ThemeEnvy.outputPath}/assets/theme-envy.critical.css`]
17
- if (mode === 'production') tailwindOpts.push('--minify')
18
- if (watch) tailwindOpts.push('--watch')
19
- const tailwindOutput = verbose ? { stdio: 'inherit' } : {}
20
- const tailwindProcess = spawn('npx', tailwindOpts, tailwindOutput)
21
- if (watch) {
22
- // watch process does not exit, so we need to increment the progress bar and resolve the promise
23
- ThemeEnvy.progress.increment('tailwind')
24
- resolve()
25
- }
26
- tailwindProcess.on('exit', () => {
27
- ThemeEnvy.progress.increment('tailwind')
28
- resolve()
29
- })
30
- })
31
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * @private
3
- * @file Checks for a parent theme in node_modules or relative path and sets ThemeEnvy.parentTheme to the path
4
- */
5
-
6
- const fs = require('fs-extra')
7
- const path = require('path');
8
-
9
- (() => {
10
- const ThemeConfigPath = path.resolve(process.cwd(), 'theme.config.js')
11
- if (!fs.existsSync(ThemeConfigPath)) return
12
- ThemeEnvy.childPreferred = ThemeEnvy.childPreferred || []
13
-
14
- // look for parent theme in node_modules
15
- const parentThemePath = ThemeEnvy.parentTheme?.path
16
- if (!parentThemePath) return
17
- const parentThemePkg = fs.existsSync(path.resolve(process.cwd(), 'node_modules', parentThemePath))
18
- ? path.resolve(process.cwd(), 'node_modules', parentThemePath)
19
- : false
20
- // look for parent theme in relative path
21
- const parentThemeRelative = fs.existsSync(path.resolve(process.cwd(), parentThemePath))
22
- ? path.resolve(process.cwd(), parentThemePath)
23
- : false
24
- // prefer node_modules over relative path
25
- const parentTheme = parentThemePkg || parentThemeRelative
26
-
27
- ThemeEnvy.parentTheme = parentTheme
28
- })()
@@ -1,3 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;