@maizzle/framework 3.7.2 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.github/workflows/nodejs.yml +28 -29
  2. package/package.json +87 -84
  3. package/src/generators/output/to-disk.js +139 -111
  4. package/src/generators/output/to-string.js +5 -2
  5. package/src/generators/posthtml.js +61 -60
  6. package/src/generators/tailwindcss.js +49 -18
  7. package/src/index.js +24 -36
  8. package/src/transformers/{attribute-to-style.js → attributeToStyle.js} +0 -0
  9. package/src/transformers/baseUrl.js +45 -0
  10. package/src/transformers/{extra-attributes.js → extraAttributes.js} +0 -0
  11. package/src/transformers/index.js +57 -57
  12. package/src/transformers/{inline.js → inlineCss.js} +0 -0
  13. package/src/transformers/{posthtml-mso.js → posthtmlMso.js} +0 -0
  14. package/src/transformers/{prevent-widows.js → preventWidows.js} +0 -0
  15. package/src/transformers/{remove-attributes.js → removeAttributes.js} +1 -1
  16. package/src/transformers/{remove-inline-bgcolor.js → removeInlineBackgroundColor.js} +0 -0
  17. package/src/transformers/{remove-inline-sizes.js → removeInlineSizes.js} +0 -0
  18. package/src/transformers/{remove-unused-css.js → removeUnusedCss.js} +0 -0
  19. package/src/transformers/{replace-strings.js → replaceStrings.js} +0 -0
  20. package/src/transformers/{safe-class-names.js → safeClassNames.js} +8 -2
  21. package/src/transformers/{six-hex.js → sixHex.js} +10 -10
  22. package/src/transformers/transform.js +4 -6
  23. package/src/transformers/{url-params.js → urlParameters.js} +0 -0
  24. package/src/utils/helpers.js +2 -8
  25. package/test/expected/transformers/base-image-url.html +83 -7
  26. package/test/expected/transformers/transform-postcss.html +19 -0
  27. package/test/expected/useConfig.html +9 -0
  28. package/test/fixtures/transformers/base-image-url.html +85 -7
  29. package/test/fixtures/useConfig.html +9 -0
  30. package/test/stubs/tailwind/preserve.html +1 -0
  31. package/test/test-misc.js +8 -8
  32. package/test/test-tailwind.js +100 -73
  33. package/test/test-todisk.js +70 -28
  34. package/test/test-tostring.js +8 -0
  35. package/test/test-transformers.js +343 -320
  36. package/xo.config.js +22 -19
  37. package/src/transformers/base-image-url.js +0 -9
@@ -9,7 +9,7 @@ const mergeLonghand = require('postcss-merge-longhand')
9
9
  const {get, isObject, isEmpty, merge} = require('lodash')
10
10
 
11
11
  module.exports = {
12
- compile: async (css = '', html = '', tailwindConfig = {}, maizzleConfig = {}) => {
12
+ compile: async (css = '', html = '', tailwindConfig = {}, maizzleConfig = {}, spinner = null) => {
13
13
  tailwindConfig = (isObject(tailwindConfig) && !isEmpty(tailwindConfig)) ? tailwindConfig : get(maizzleConfig, 'build.tailwind.config', 'tailwind.config.js')
14
14
 
15
15
  // Compute the Tailwind config to use
@@ -33,15 +33,14 @@ module.exports = {
33
33
  // Merge user's Tailwind config on top of a 'base' config
34
34
  const config = merge({
35
35
  important: true,
36
- purge: {
37
- enabled: maizzleConfig.env !== 'local',
38
- content: [
39
- 'src/**/*.*',
40
- {raw: html}
41
- ],
42
- options: get(maizzleConfig, 'purgeCSS', {})
36
+ content: {
37
+ files: [
38
+ './src/**/*.*',
39
+ {raw: html, extension: 'html'}
40
+ ]
43
41
  },
44
42
  corePlugins: {
43
+ preflight: false,
45
44
  animation: false,
46
45
  backgroundOpacity: false,
47
46
  borderOpacity: false,
@@ -57,22 +56,46 @@ module.exports = {
57
56
  plugins: []
58
57
  }, userConfig())
59
58
 
59
+ // Add back the `{raw: html}` option if user provided own config
60
+ if (Array.isArray(config.content)) {
61
+ config.content = {
62
+ files: [
63
+ ...config.content,
64
+ './src/**/*.*',
65
+ {raw: html, extension: 'html'}
66
+ ]
67
+ }
68
+ }
69
+
70
+ // Include all `build.templates.source` paths when scanning for selectors to preserve
71
+ const buildTemplates = get(maizzleConfig, 'build.templates')
72
+
73
+ if (buildTemplates) {
74
+ const templateObjects = Array.isArray(buildTemplates) ? buildTemplates : [buildTemplates]
75
+ const templateSources = templateObjects.map(template => {
76
+ const source = get(template, 'source')
77
+
78
+ return `${source}/**/*.*`
79
+ })
80
+
81
+ config.content.files.push(...templateSources)
82
+ }
83
+
60
84
  // Merge user's Tailwind plugins with our default ones
61
- config.plugins.push(require('tailwindcss-box-shadow'))
85
+ config.plugins = [
86
+ ...config.plugins,
87
+ require('tailwindcss-box-shadow')
88
+ ]
62
89
 
63
90
  const userFilePath = get(maizzleConfig, 'build.tailwind.css', path.join(process.cwd(), 'src/css/tailwind.css'))
91
+ const userFileExists = await fs.pathExists(userFilePath)
64
92
 
65
- css = await fs.pathExists(userFilePath).then(async exists => {
66
- if (exists) {
67
- const userFileCSS = await fs.readFile(path.resolve(userFilePath), 'utf8')
68
- return userFileCSS
69
- }
70
-
71
- return css
72
- })
93
+ if (userFileExists) {
94
+ css = await fs.readFile(path.resolve(userFilePath), 'utf8')
95
+ }
73
96
 
74
97
  return postcss([
75
- postcssImport({path: userFilePath ? path.dirname(userFilePath) : []}),
98
+ postcssImport({path: path.dirname(userFilePath)}),
76
99
  postcssNested(),
77
100
  tailwindcss(config),
78
101
  maizzleConfig.env === 'local' ? () => {} : mergeLonghand(),
@@ -80,5 +103,13 @@ module.exports = {
80
103
  ])
81
104
  .process(css, {from: undefined})
82
105
  .then(result => result.css)
106
+ .catch(error => {
107
+ console.error(error)
108
+ if (spinner) {
109
+ spinner.stop()
110
+ }
111
+
112
+ throw new Error(`Tailwind CSS compilation failed`)
113
+ })
83
114
  }
84
115
  }
package/src/index.js CHANGED
@@ -2,13 +2,20 @@ const ora = require('ora')
2
2
  const path = require('path')
3
3
  const fs = require('fs-extra')
4
4
  const {get, merge} = require('lodash')
5
- const bs = require('browser-sync').create()
6
5
  const Config = require('./generators/config')
7
6
  const Output = require('./generators/output')
8
7
  const transformers = require('./transformers')
9
8
  const {clearConsole} = require('./utils/helpers')
10
9
  const Plaintext = require('./generators/plaintext')
11
- const Tailwind = require('./generators/tailwindcss')
10
+
11
+ const getBrowserSync = () => {
12
+ if (!global.cachedBrowserSync) {
13
+ const bs = require('browser-sync')
14
+ global.cachedBrowserSync = bs.create()
15
+ }
16
+
17
+ return global.cachedBrowserSync
18
+ }
12
19
 
13
20
  const self = module.exports = { // eslint-disable-line
14
21
  ...transformers,
@@ -23,7 +30,10 @@ const self = module.exports = { // eslint-disable-line
23
30
  const elapsedSeconds = (Date.now() - start) / 1000
24
31
 
25
32
  if (get(config, 'build.command') === 'serve') {
26
- clearConsole()
33
+ if (get(config, 'build.console.clear')) {
34
+ clearConsole()
35
+ }
36
+
27
37
  spinner.succeed(`Re-built ${parsed.length} templates in ${elapsedSeconds}s`)
28
38
  } else {
29
39
  spinner.succeed(`Built ${parsed.length} templates in ${elapsedSeconds}s`)
@@ -59,16 +69,14 @@ const self = module.exports = { // eslint-disable-line
59
69
  [...new Set(get(config, 'build.browsersync.watch', []))]
60
70
  ]
61
71
 
62
- // Pre-compile Tailwind so that updates to tailwind.config.js are reflected
63
- const cssString = fs.existsSync(get(config, 'build.tailwind.css')) ? fs.readFileSync(get(config, 'build.tailwind.css'), 'utf8') : '@tailwind components; @tailwind utilities;'
64
- const css = await Tailwind.compile(cssString, '', {}, config)
65
-
66
72
  const spinner = ora()
67
73
 
68
74
  // Watch for Template file changes
69
- bs.watch(templatePaths)
75
+ getBrowserSync().watch(templatePaths)
70
76
  .on('change', async file => {
71
- clearConsole()
77
+ if (get(config, 'build.console.clear')) {
78
+ clearConsole()
79
+ }
72
80
 
73
81
  const start = new Date()
74
82
 
@@ -86,54 +94,34 @@ const self = module.exports = { // eslint-disable-line
86
94
  await config.events.beforeCreate(config)
87
95
  }
88
96
 
89
- /**
90
- * Tailwind CSS compiler
91
- *
92
- * Use the Just-In-Time engine if the user enabled it
93
- * Fall back to the classic Always-On-Time engine
94
- */
95
- let mode = 'aot'
96
-
97
- try {
98
- const tailwindConfig = require(path.resolve(process.cwd(), get(config, 'build.currentTemplates.tailwind.config', 'tailwind.config.js')))
99
- mode = get(tailwindConfig, 'mode')
100
- } catch {}
101
-
102
97
  const renderOptions = {
103
98
  maizzle: config,
104
99
  ...config.events
105
100
  }
106
101
 
107
- // AOT: fall back to pre-compiled CSS
108
- if (mode !== 'jit') {
109
- renderOptions.tailwind = {
110
- compiled: css
111
- }
112
- }
113
-
114
102
  self
115
103
  .render(await fs.readFile(file, 'utf8'), renderOptions)
116
104
  .then(({html, config}) => fs.outputFile(config.permalink || finalDestination, html))
117
105
  .then(() => {
118
- bs.reload()
106
+ getBrowserSync().reload()
119
107
  spinner.succeed(`Compiled in ${(Date.now() - start) / 1000}s [${file}]`)
120
108
  })
121
109
  .catch(() => spinner.warn(`Received empty HTML, please save your file again [${file}]`))
122
110
  })
123
111
 
124
112
  // Watch for changes in all other files
125
- bs.watch(globalPaths, {ignored: templatePaths})
126
- .on('change', () => self.build(env, config).then(() => bs.reload()))
127
- .on('unlink', () => self.build(env, config).then(() => bs.reload()))
113
+ getBrowserSync().watch(globalPaths, {ignored: templatePaths})
114
+ .on('change', () => self.build(env, config).then(() => getBrowserSync().reload()))
115
+ .on('unlink', () => self.build(env, config).then(() => getBrowserSync().reload()))
128
116
 
129
117
  // Watch for changes in config files
130
- bs.watch('config*.js')
118
+ getBrowserSync().watch('config*.js')
131
119
  .on('change', async file => {
132
120
  const parsedEnv = path.parse(file).name.split('.')[1] || 'local'
133
121
 
134
122
  Config
135
123
  .getMerged(parsedEnv)
136
- .then(config => self.build(parsedEnv, config).then(() => bs.reload()))
124
+ .then(config => self.build(parsedEnv, config).then(() => getBrowserSync().reload()))
137
125
  })
138
126
 
139
127
  // Browsersync options
@@ -154,7 +142,7 @@ const self = module.exports = { // eslint-disable-line
154
142
  }
155
143
 
156
144
  // Initialize Browsersync
157
- bs.init(bsOptions, () => {})
145
+ getBrowserSync().init(bsOptions, () => {})
158
146
  })
159
147
  .catch(error => {
160
148
  throw error
@@ -0,0 +1,45 @@
1
+ const posthtml = require('posthtml')
2
+ const isUrl = require('is-url-superb')
3
+ const baseUrl = require('posthtml-base-url')
4
+ const {get, isObject, isEmpty} = require('lodash')
5
+
6
+ // VML backgrounds need regex because they're inside HTML comments :(
7
+ const rewriteVMLs = (html, url) => {
8
+ const vImageMatch = html.match(/(<v:image.+)(src=['"]([^'"]+)['"])/)
9
+ const vFillMatch = html.match(/(<v:fill.+)(src=['"]([^'"]+)['"])/)
10
+
11
+ if (!isUrl(vImageMatch[3])) {
12
+ html = html.replace(vImageMatch[0], `${vImageMatch[1]}src="${url}${vImageMatch[3]}"`)
13
+ }
14
+
15
+ if (!isUrl(vFillMatch[3])) {
16
+ html = html.replace(vFillMatch[0], `${vFillMatch[1]}src="${url}${vFillMatch[3]}"`)
17
+ }
18
+
19
+ return html
20
+ }
21
+
22
+ module.exports = async (html, config = {}, direct = false) => {
23
+ const url = direct ? config : get(config, 'baseURL')
24
+ const posthtmlOptions = get(config, 'build.posthtml.options', {})
25
+
26
+ // `baseUrl` as a string
27
+ if (typeof url === 'string' && url.length > 0) {
28
+ html = rewriteVMLs(html, url)
29
+
30
+ return posthtml([
31
+ baseUrl({url, allTags: true, styleTag: true, inlineCss: true})
32
+ ])
33
+ .process(html, posthtmlOptions)
34
+ .then(result => result.html)
35
+ }
36
+
37
+ // `baseUrl: {}`
38
+ if (isObject(url) && !isEmpty(url)) {
39
+ html = rewriteVMLs(html, url.url)
40
+
41
+ return posthtml([baseUrl(url)]).process(html, posthtmlOptions).then(result => result.html)
42
+ }
43
+
44
+ return html
45
+ }
@@ -1,57 +1,57 @@
1
- const inline = require('./inline')
2
- const minify = require('./minify')
3
- const markdown = require('./markdown')
4
- const prettify = require('./prettify')
5
- const ensureSixHEX = require('./six-hex')
6
- const addURLParams = require('./url-params')
7
- const transformContents = require('./transform')
8
- const preventWidows = require('./prevent-widows')
9
- const replaceStrings = require('./replace-strings')
10
- const safeClassNames = require('./safe-class-names')
11
- const applyBaseImageUrl = require('./base-image-url')
12
- const removeUnusedCSS = require('./remove-unused-css')
13
- const removeAttributes = require('./remove-attributes')
14
- const attributeToStyle = require('./attribute-to-style')
15
- const removeInlineSizes = require('./remove-inline-sizes')
16
- const applyExtraAttributes = require('./extra-attributes')
17
- const removeInlineBgColor = require('./remove-inline-bgcolor')
18
-
19
- exports.process = async (html, config) => {
20
- html = await safeClassNames(html, config)
21
- html = await transformContents(html, config)
22
- html = await markdown(html, config)
23
- html = await preventWidows(html, config)
24
- html = await attributeToStyle(html, config)
25
- html = await inline(html, config)
26
- html = await removeUnusedCSS(html, config)
27
- html = await removeInlineSizes(html, config)
28
- html = await removeInlineBgColor(html, config)
29
- html = await removeAttributes(html, config)
30
- html = await applyExtraAttributes(html, config)
31
- html = await applyBaseImageUrl(html, config)
32
- html = await addURLParams(html, config)
33
- html = await ensureSixHEX(html, config)
34
- html = await prettify(html, config)
35
- html = await minify(html, config)
36
- html = await replaceStrings(html, config)
37
-
38
- return html
39
- }
40
-
41
- exports.inlineCSS = (html, config) => inline(html, config, true)
42
- exports.minify = (html, config) => minify(html, config, true)
43
- exports.markdown = (html, config) => markdown(html, config, true)
44
- exports.prettify = (html, config) => prettify(html, config, true)
45
- exports.ensureSixHEX = (html, config) => ensureSixHEX(html, config)
46
- exports.addURLParams = (html, config) => addURLParams(html, config, true)
47
- exports.transformContents = (html, config) => transformContents(html, config, true)
48
- exports.preventWidows = (html, config) => preventWidows(html, config, true)
49
- exports.replaceStrings = (html, config) => replaceStrings(html, config, true)
50
- exports.safeClassNames = (html, config) => safeClassNames(html, config, true)
51
- exports.applyBaseImageUrl = (html, config) => applyBaseImageUrl(html, config, true)
52
- exports.removeUnusedCSS = (html, config) => removeUnusedCSS(html, config, true)
53
- exports.removeAttributes = (html, config) => removeAttributes(html, config, true)
54
- exports.removeInlineSizes = (html, config) => removeInlineSizes(html, config, true)
55
- exports.applyExtraAttributes = (html, config) => applyExtraAttributes(html, config, true)
56
- exports.removeInlineBgColor = (html, config) => removeInlineBgColor(html, config, true)
57
- exports.attributeToStyle = (html, config) => attributeToStyle(html, config, true)
1
+ const inline = require('./inlineCss')
2
+ const minify = require('./minify')
3
+ const markdown = require('./markdown')
4
+ const prettify = require('./prettify')
5
+ const ensureSixHEX = require('./sixHex')
6
+ const applyBaseImageUrl = require('./baseUrl')
7
+ const addURLParams = require('./urlParameters')
8
+ const transformContents = require('./transform')
9
+ const preventWidows = require('./preventWidows')
10
+ const replaceStrings = require('./replaceStrings')
11
+ const safeClassNames = require('./safeClassNames')
12
+ const removeUnusedCSS = require('./removeUnusedCss')
13
+ const removeAttributes = require('./removeAttributes')
14
+ const attributeToStyle = require('./attributeToStyle')
15
+ const removeInlineSizes = require('./removeInlineSizes')
16
+ const applyExtraAttributes = require('./extraAttributes')
17
+ const removeInlineBgColor = require('./removeInlineBackgroundColor')
18
+
19
+ exports.process = async (html, config) => {
20
+ html = await safeClassNames(html, config)
21
+ html = await transformContents(html, config)
22
+ html = await markdown(html, config)
23
+ html = await preventWidows(html, config)
24
+ html = await attributeToStyle(html, config)
25
+ html = await inline(html, config)
26
+ html = await removeUnusedCSS(html, config)
27
+ html = await removeInlineSizes(html, config)
28
+ html = await removeInlineBgColor(html, config)
29
+ html = await removeAttributes(html, config)
30
+ html = await applyExtraAttributes(html, config)
31
+ html = await applyBaseImageUrl(html, config)
32
+ html = await addURLParams(html, config)
33
+ html = await ensureSixHEX(html, config)
34
+ html = await prettify(html, config)
35
+ html = await minify(html, config)
36
+ html = await replaceStrings(html, config)
37
+
38
+ return html
39
+ }
40
+
41
+ exports.inlineCSS = (html, config) => inline(html, config, true)
42
+ exports.minify = (html, config) => minify(html, config, true)
43
+ exports.markdown = (html, config) => markdown(html, config, true)
44
+ exports.prettify = (html, config) => prettify(html, config, true)
45
+ exports.ensureSixHEX = (html, config) => ensureSixHEX(html, config)
46
+ exports.addURLParams = (html, config) => addURLParams(html, config, true)
47
+ exports.transformContents = (html, config) => transformContents(html, config, true)
48
+ exports.preventWidows = (html, config) => preventWidows(html, config, true)
49
+ exports.replaceStrings = (html, config) => replaceStrings(html, config, true)
50
+ exports.safeClassNames = (html, config) => safeClassNames(html, config, true)
51
+ exports.applyBaseImageUrl = (html, config) => applyBaseImageUrl(html, config, true)
52
+ exports.removeUnusedCSS = (html, config) => removeUnusedCSS(html, config, true)
53
+ exports.removeAttributes = (html, config) => removeAttributes(html, config, true)
54
+ exports.removeInlineSizes = (html, config) => removeInlineSizes(html, config, true)
55
+ exports.applyExtraAttributes = (html, config) => applyExtraAttributes(html, config, true)
56
+ exports.removeInlineBgColor = (html, config) => removeInlineBgColor(html, config, true)
57
+ exports.attributeToStyle = (html, config) => attributeToStyle(html, config, true)
File without changes
@@ -8,7 +8,7 @@ module.exports = async (html, config = {}, direct = false) => {
8
8
 
9
9
  attributes.push({name: 'style'}, {name: 'class'})
10
10
 
11
- // Allow ommiting `value` key when removing empty attributes
11
+ // Allow omitting `value` key when removing empty attributes
12
12
  attributes.forEach(attr => {
13
13
  attr.value = attr.value || ''
14
14
  })
@@ -3,11 +3,17 @@ const posthtml = require('posthtml')
3
3
  const safeClassNames = require('posthtml-safe-class-names')
4
4
 
5
5
  module.exports = async (html, config = {}, direct = false) => {
6
- if (get(config, 'safeClassNames') === false) {
6
+ const option = get(config, 'safeClassNames')
7
+
8
+ if (option === false) {
7
9
  return html
8
10
  }
9
11
 
10
- if (config.env === 'local') {
12
+ /*
13
+ * Setting it to `true` in the config will run `safeClassNames`
14
+ * no matter the environment.
15
+ */
16
+ if (config.env === 'local' && !option) {
11
17
  return html
12
18
  }
13
19
 
@@ -1,10 +1,10 @@
1
- const {get} = require('lodash')
2
- const {conv} = require('color-shorthand-hex-to-six-digit')
3
-
4
- module.exports = async (html, config = {}) => {
5
- if (get(config, 'sixHex') === false) {
6
- return html
7
- }
8
-
9
- return conv(html)
10
- }
1
+ const {get} = require('lodash')
2
+ const {conv} = require('color-shorthand-hex-to-six-digit')
3
+
4
+ module.exports = async (html, config = {}) => {
5
+ if (get(config, 'sixHex') === false) {
6
+ return html
7
+ }
8
+
9
+ return conv(html)
10
+ }
@@ -13,12 +13,10 @@ module.exports = async (html, config = {}, direct = false) => {
13
13
  const maizzleConfig = omit(config, ['build.tailwind.css', 'css'])
14
14
  const tailwindConfig = get(config, 'build.tailwind.config', 'tailwind.config.js')
15
15
 
16
- replacements.postcss = css => Tailwind.compile(
17
- `@tailwind components; @tailwind utilities; ${css}`,
18
- html,
19
- tailwindConfig,
20
- maizzleConfig
21
- )
16
+ const compileCss = css => Tailwind.compile(css, html, tailwindConfig, maizzleConfig)
17
+
18
+ replacements.tailwindcss = css => compileCss(`@tailwind components; @tailwind utilities; ${css}`)
19
+ replacements.postcss = css => compileCss(`@tailwind components; @tailwind utilities; ${css}`)
22
20
 
23
21
  return posthtml([posthtmlContent(replacements)]).process(html, posthtmlOptions).then(result => result.html)
24
22
  }
@@ -1,5 +1,3 @@
1
- const readline = require('readline')
2
-
3
1
  module.exports = {
4
2
  asyncForEach: async (array, callback) => {
5
3
  for (let index = 0; index < array.length; index++) {
@@ -14,10 +12,6 @@ module.exports = {
14
12
  throw new Error(`could not load ${module}`)
15
13
  }
16
14
  },
17
- clearConsole: () => {
18
- const blank = '\n'.repeat(process.stdout.rows)
19
- console.log(blank)
20
- readline.cursorTo(process.stdout, 0, 0)
21
- readline.clearScreenDown(process.stdout)
22
- }
15
+ // https://github.com/lukeed/console-clear
16
+ clearConsole: () => process.stdout.write('\x1B[H\x1B[2J')
23
17
  }
@@ -1,7 +1,83 @@
1
- <div style="background-image: url('https://example.com/foo/bar.jpg')">
2
- <img src="https://example.com/logo.png" srcset="https://example.com/assets/logo.png 1x, https://example.com/assets/logo@2x.png 2x">
3
- </div>
4
-
5
- <div style="background: url(https://example.com/foo/bar.jpg)">
6
- <img background="https://example.com/example.jpg" srcset="https://example.com/example.jpg 1x, https://example.com/example@2x.jpg 2x">
7
- </div>
1
+ <html>
2
+ <head>
3
+ <style>.test {
4
+ background-image: url('https://example.com/image.jpg');
5
+ background: url('https://example.com/image.jpg');
6
+ background-image: url('https://preserve.me/image.jpg');
7
+ background: url('https://preserve.me/image.jpg');
8
+ }
9
+
10
+ .test-2 {
11
+ background-image: url("https://example.com/image.jpg");
12
+ background: url("https://example.com/image.jpg");
13
+ background-image: url("https://preserve.me/image.jpg");
14
+ background: url("https://preserve.me/image.jpg");
15
+ }
16
+
17
+ .test-3 {
18
+ background-image: url(https://example.com/image.jpg);
19
+ background: url(https://example.com/image.jpg);
20
+ background-image: url(https://preserve.me/image.jpg);
21
+ background: url(https://preserve.me/image.jpg);
22
+ }</style>
23
+ </head>
24
+
25
+ <body>
26
+ <img src="https://example.com/test.jpg">
27
+ <img src="https://example.com/test.jpg">
28
+
29
+ <img src="https://example.com/image1.jpg" srcset="https://example.com/image1-HD.jpg 2x, https://example.com/image1-phone.jpg 100w">
30
+
31
+ <img src="https://example.com/image2.jpg" srcset="https://example.com/image2-HD.jpg 2x, https://example.com/image2-phone.jpg 100w">
32
+
33
+ <picture>
34
+ <source media="(max-width: 799px)" srcset="https://example.com/elva-480w-close-portrait.jpg">
35
+ <source media="(min-width: 800px)" srcset="https://example.com/elva-800w.jpg">
36
+ <img src="https://example.com/elva-800w.jpg" alt="...">
37
+ </picture>
38
+
39
+ <video width="250" poster="https://example.com/flower.jpg">
40
+ <source src="https://example.com/media/flower.webm" type="video/webm">
41
+ <source src="https://example.tv/media/flower.mp4" type="video/mp4">
42
+ <track default="" kind="captions" srclang="en" src="https://example.com/media/tracks/friday.vtt">
43
+ </video>
44
+
45
+ <audio src="https://example.com/media/sample.mp3">
46
+ Fallback content
47
+ </audio>
48
+
49
+ <embed type="video/webm" src="https://example.com/media/flower.mp4" width="250" height="200">
50
+
51
+ <iframe width="300" height="200" src="https://example.com/embed.html"></iframe>
52
+
53
+ <input type="image" src="https://example.com/image.jpg" alt="">
54
+
55
+ <script src="https://example.com/javascript.js"></script>
56
+
57
+ <div>
58
+ <!--[if mso]>
59
+ <v:image xmlns:v="urn:schemas-microsoft-com:vml" src="https://example.com/image.jpg" style="600px;height:400px;" />
60
+ <v:rect fill="false" stroke="false" style="position:absolute;600px;height:400px;">
61
+ <v:textbox inset="0,0,0,0"><div><![endif]-->
62
+ <div>test</div>
63
+ <!--[if mso]></div></v:textbox></v:rect><![endif]-->
64
+ </div>
65
+
66
+ <table>
67
+ <tr>
68
+ <td background="https://example.com/image.png" bgcolor="#7bceeb" width="120" height="92" valign="top">
69
+ <!--[if gte mso 9]>
70
+ <v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:120px;height:92px;">
71
+ <v:fill type="tile" src="https://example.com/image.png" color="#7bceeb" />
72
+ <v:textbox inset="0,0,0,0">
73
+ <![endif]-->
74
+ <div>test</div>
75
+ <!--[if gte mso 9]>
76
+ </v:textbox>
77
+ </v:rect>
78
+ <![endif]-->
79
+ </td>
80
+ </tr>
81
+ </table>
82
+ </body>
83
+ </html>
@@ -0,0 +1,19 @@
1
+ <style>.inline { display: inline !important
2
+ } .table { display: table !important
3
+ } .contents { display: contents !important
4
+ } .hidden { display: none !important
5
+ } .transform { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) !important
6
+ } div { width: 100%
7
+ } @media (min-width: 640px) { div { max-width: 640px
8
+ }
9
+ } @media (min-width: 768px) { div { max-width: 768px
10
+ }
11
+ } @media (min-width: 1024px) { div { max-width: 1024px
12
+ }
13
+ } @media (min-width: 1280px) { div { max-width: 1280px
14
+ }
15
+ } @media (min-width: 1536px) { div { max-width: 1536px
16
+ }
17
+ } div { display: none
18
+ }
19
+ </style>
@@ -0,0 +1,9 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>test></title>
5
+ </head>
6
+ <body>
7
+ <div>build_production</div>
8
+ </body>
9
+ </html>