@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.
- package/build/functions/get-all.js +34 -15
- package/build/functions/index.js +0 -1
- package/build/functions/liquid/functions/list-dependencies.js +1 -1
- package/build/functions/liquid/functions/section-schema-inject.js +44 -4
- package/build/functions/parent-theme/index.js +77 -0
- package/build/functions/parent-theme/parent-theme-files.js +46 -0
- package/build/functions/webpack-plugins/retry-chunk-load-plugin.js +88 -0
- package/build/functions/webpack.js +24 -1
- package/build/index.js +3 -4
- package/build/requires/assets.js +2 -3
- package/build/requires/globals/index.js +0 -1
- package/build/requires/globals/prepare-install-hooks-schema.js +1 -2
- package/build/requires/globals/progress-bar.js +1 -2
- package/build/requires/globals/theme-require.js +11 -9
- package/build/requires/locales.js +13 -8
- package/build/requires/scripts/script-builders/elements.build.js +29 -21
- package/build/requires/styles/styles-builders/theme-envy.css.js +5 -1
- package/build/theme-envy.config.js +18 -7
- package/helpers/functions/parse-schema.js +20 -0
- package/helpers/functions/pull-json.js +1 -1
- package/helpers/index.js +1 -0
- package/index.js +1 -0
- package/init/functions/copy-starter-config-files/configs/postcss.config.js +7 -7
- package/init/functions/copy-starter-config-files/configs/tailwind.config.js +18 -4
- package/init/functions/copy-starter-config-files/configs/theme.config.js +1 -1
- package/package.json +10 -10
- package/build/functions/parent-theme-files.js +0 -25
- package/build/functions/tailwind.js +0 -31
- package/build/requires/globals/parent-theme.js +0 -28
- 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
|
|
32
|
+
return globSync(src, '**/assets/**/*')
|
|
20
33
|
},
|
|
21
34
|
},
|
|
22
35
|
config: {
|
|
23
36
|
glob(src) {
|
|
24
|
-
return
|
|
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
|
|
43
|
+
return globSync(src, '**/critical.css')
|
|
31
44
|
},
|
|
32
45
|
},
|
|
33
46
|
elements: {
|
|
34
47
|
glob(src) {
|
|
35
|
-
return [...
|
|
48
|
+
return [...globSync(src, '**/elements/**/index.js'), ...globSync(src, '**/elements/*.js')]
|
|
36
49
|
}
|
|
37
50
|
},
|
|
38
51
|
features: {
|
|
39
52
|
glob(src) {
|
|
40
|
-
return
|
|
53
|
+
return globSync(src, '**/features/**/index.js')
|
|
41
54
|
},
|
|
42
55
|
},
|
|
43
56
|
installs: {
|
|
44
57
|
glob(src) {
|
|
45
|
-
return
|
|
58
|
+
return globSync(src, '**/install.js')
|
|
46
59
|
},
|
|
47
60
|
},
|
|
48
61
|
liquid: {
|
|
49
62
|
glob(src) {
|
|
50
|
-
return
|
|
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
|
|
74
|
+
return globSync(src, '**/partials/**/*.liquid')
|
|
57
75
|
},
|
|
58
76
|
},
|
|
59
77
|
schema: {
|
|
60
78
|
glob(src) {
|
|
61
|
-
return
|
|
79
|
+
return globSync(src, '**/schema/**/*.js')
|
|
62
80
|
},
|
|
63
81
|
},
|
|
64
82
|
sectionGroups: {
|
|
65
83
|
glob(src) {
|
|
66
|
-
return
|
|
84
|
+
return globSync(src, '**/sections/**/*.json')
|
|
67
85
|
},
|
|
68
86
|
},
|
|
69
87
|
snippets: {
|
|
70
88
|
glob(src) {
|
|
71
|
-
return
|
|
89
|
+
return globSync(src, '**/snippets/**/*.liquid')
|
|
72
90
|
},
|
|
73
91
|
},
|
|
74
92
|
templates: {
|
|
75
93
|
glob(src) {
|
|
76
|
-
return
|
|
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
|
|
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.
|
|
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)
|
package/build/functions/index.js
CHANGED
|
@@ -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 =>
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
if (
|
|
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(
|
|
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
|
|
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')
|
package/build/requires/assets.js
CHANGED
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs-extra')
|
|
6
6
|
const path = require('path')
|
|
7
|
-
const
|
|
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'))
|
|
@@ -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].
|
|
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:
|
|
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
|
-
//
|
|
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(
|
|
92
|
+
content = schemaLoop(content, options.loop)
|
|
91
93
|
}
|
|
92
94
|
if (options?.suffix) {
|
|
93
|
-
content = schemaSuffix(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 = {
|
|
15
|
+
? `const elements = {
|
|
16
|
+
${elements.join(',\n ')}}
|
|
16
17
|
// check all elements for presence in the Document and load if they are there
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (domElm
|
|
21
|
-
|
|
22
|
-
entries
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
content: [
|
|
8
|
+
const config = {
|
|
9
|
+
content: [
|
|
10
|
+
path.resolve(ThemeEnvy.themePath, '**/*.{liquid,js}'),
|
|
11
|
+
],
|
|
11
12
|
theme: {
|
|
12
13
|
extend: {},
|
|
13
14
|
},
|
|
14
|
-
screens:
|
|
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softlimit/theme-envy",
|
|
3
|
-
"version": "0.1.
|
|
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.
|
|
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": "^
|
|
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.
|
|
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
|
-
"
|
|
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
|
-
})()
|