const fs = require('fs') const path = require('path') const postcss = require('postcss') const tailwind = require('../src/index.js') const sharedState = require('../src/lib/sharedState.js') const configPath = path.resolve(__dirname, './context-reuse.tailwind.config.js') const { css } = require('./util/run.js') function run(input, config = {}, from = null) { let { currentTestName } = expect.getState() from = `${path.resolve(__filename)}?test=${currentTestName}&${from}` return postcss(tailwind(config)).process(input, { from }) } beforeEach(async () => { let config = { content: [path.resolve(__dirname, './context-reuse.test.html')], corePlugins: { preflight: false }, } await fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) }) afterEach(async () => { await fs.promises.unlink(configPath) }) it('re-uses the context across multiple files with the same config', async () => { let results = [ await run(`@tailwind utilities;`, configPath, `id=1`), // Using @apply directives should still re-use the context // They depend on the config but do not the other way around await run(`body { @apply bg-blue-400; }`, configPath, `id=2`), await run(`body { @apply text-red-400; }`, configPath, `id=3`), await run(`body { @apply mb-4; }`, configPath, `id=4`), ] let dependencies = results.map((result) => { return result.messages .filter((message) => message.type === 'dependency') .map((message) => message.file) }) // The content files don't have any utilities in them so this should be empty expect(results[0].css).toMatchFormattedCss(css``) // However, @apply is being used so we want to verify that they're being inlined into the CSS rules expect(results[1].css).toMatchFormattedCss(css` body { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } `) expect(results[2].css).toMatchFormattedCss(css` body { --tw-text-opacity: 1; color: rgb(248 113 113 / var(--tw-text-opacity)); } `) expect(results[3].css).toMatchFormattedCss(css` body { margin-bottom: 1rem; } `) // Files with @tailwind directives depends on the PostCSS tree, config, AND any content files expect(dependencies[0]).toEqual([ path.resolve(__dirname, 'context-reuse.test.html'), path.resolve(__dirname, 'context-reuse.tailwind.config.js'), ]) // @apply depends only on the containing PostCSS tree *and* the config file but no content files // as they cannot affect the outcome of the @apply directives expect(dependencies[1]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) expect(dependencies[2]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) expect(dependencies[3]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) // And none of this should have resulted in multiple contexts being created expect(sharedState.contextSourcesMap.size).toBe(1) }) it('updates layers when any CSS containing @tailwind directives changes', async () => { let result // Compile the initial version once let input = css` @tailwind utilities; @layer utilities { .custom-utility { color: orange; } } ` result = await run(input, configPath, `id=1`) expect(result.css).toMatchFormattedCss(css` .only\:custom-utility:only-child { color: orange; } `) // Save the file with a change input = css` @tailwind utilities; @layer utilities { .custom-utility { color: blue; } } ` result = await run(input, configPath, `id=1`) expect(result.css).toMatchFormattedCss(css` .only\:custom-utility:only-child { color: blue; } `) })