Skip to content

Commit

Permalink
fix(webpack): combine all css in one file (#230)
Browse files Browse the repository at this point in the history
Splitting can be activated by settings `css.split: true` in project config.
  • Loading branch information
hjvedvik committed Mar 1, 2019
1 parent b18e8e9 commit 952148d
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 22 deletions.
2 changes: 1 addition & 1 deletion gridsome/app/app.js
@@ -1,7 +1,7 @@
import Vue from 'vue'
import plugins from '~/.temp/plugins-server'
import routes from '~/.temp/routes.js'
import main from './main'
import routes from '~/.temp/routes.js'

import head from './head'
import router from './router'
Expand Down
Expand Up @@ -22,3 +22,9 @@ export default {
}
}
</script>

<style>
.is-mounted {
background: #f2f2f2;
}
</style>
Expand Up @@ -88,3 +88,9 @@ export default {
}
}
</script>

<style>
.is-mounted {
background-color: #f2f2f2;
}
</style>
15 changes: 15 additions & 0 deletions gridsome/lib/__tests__/project-basic.build.e2e.js
Expand Up @@ -169,11 +169,26 @@ test('compile scripts correctly', () => {
expect(appJS).toMatch('// ECMAScript 6 symbols shim')
})

test('compile a single css file', () => {
const files = fs.readdirSync(path.join(context, 'dist/assets/css'))
expect(files.length).toEqual(1)
})

test('remove the styles.js chunk', () => {
const files = fs.readdirSync(path.join(context, 'dist/assets/js'))
const chunk = files.find(file => file === 'styles.js')
expect(chunk).toBeUndefined()
})

test('open homepage in browser', async () => {
await page.goto('http://localhost:8080/', { waitUntil: 'networkidle2' })
await page.waitForSelector('#app.is-mounted')
})

test('load .g-image', async () => {
await page.waitForSelector('.g-image--loaded')
})

test('navigate to /docs/1', async () => {
await page.click('.doc-link-1')
await page.waitForSelector('#app.doc-template')
Expand Down
1 change: 1 addition & 0 deletions gridsome/lib/app/loadConfig.js
Expand Up @@ -29,6 +29,7 @@ module.exports = (context, options = {}, pkg = {}) => {
const plugins = []

const css = {
split: false,
loaderOptions: {
sass: {
indentedSyntax: true
Expand Down
29 changes: 28 additions & 1 deletion gridsome/lib/build.js
Expand Up @@ -183,11 +183,19 @@ async function createRenderQueue ({ routes, config, store, schema }) {
}

async function runWebpack (app) {
const compileTime = hirestime()

if (!process.stdout.isTTY) {
info(`Compiling assets...`)
}

return require('./webpack/compileAssets')(app)
const stats = await require('./webpack/compileAssets')(app)

if (app.config.css.split !== true) {
await removeStylesJsChunk(stats, app.config.outDir)
}

info(`Compile assets - ${compileTime(hirestime.S)}s`)
}

async function renderPageQueries (queue, app) {
Expand Down Expand Up @@ -279,3 +287,22 @@ async function processImages (queue, config) {

info(`Process images (${totalAssets} images) - ${timer(hirestime.S)}s`)
}

// borrowed from vuepress/core/lib/build.js
// webpack fails silently in some cases, appends styles.js to app.js to fix it
// https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85
async function removeStylesJsChunk (stats, outDir) {
const { children: [child] } = stats
const styleChunk = child.assets.find(a => /styles(\.\w{8})?\.js$/.test(a.name))
const appChunk = child.assets.find(a => /app(\.\w{8})?\.js$/.test(a.name))

if (!styleChunk) return

const styleChunkPath = path.join(outDir, styleChunk.name)
const styleChunkContent = await fs.readFile(styleChunkPath, 'utf-8')
const appChunkPath = path.join(outDir, appChunk.name)
const appChunkContent = await fs.readFile(appChunkPath, 'utf-8')

await fs.remove(styleChunkPath)
await fs.writeFile(appChunkPath, styleChunkContent + appChunkContent)
}
10 changes: 2 additions & 8 deletions gridsome/lib/webpack/compileAssets.js
@@ -1,11 +1,7 @@
const hirestime = require('hirestime')
const createClientConfig = require('./createClientConfig')
const createServerConfig = require('./createServerConfig')
const { info } = require('../utils/log')

module.exports = async (app, defines = {}) => {
const compileTime = hirestime()

const clientConfig = await createClientConfig(app)
const serverConfig = await createServerConfig(app)

Expand All @@ -20,12 +16,10 @@ module.exports = async (app, defines = {}) => {
serverConfig
})

await compile([
return compile([
clientConfig.toConfig(),
serverConfig.toConfig()
])

info(`Compile assets - ${compileTime(hirestime.S)}s`)
}

function compile (config) {
Expand All @@ -40,7 +34,7 @@ function compile (config) {
return reject(errors[0])
}

resolve()
resolve(stats.toJson({ modules: false }))
})
})
}
29 changes: 19 additions & 10 deletions gridsome/lib/webpack/createBaseConfig.js
Expand Up @@ -234,17 +234,26 @@ module.exports = (app, { isProd, isServer }) => {
filename: `${assetsDir}/css/styles${useHash ? '.[contenthash:8]' : ''}.css`
}])

config.optimization.splitChunks({
cacheGroups: {
data: {
test: m => m.resource && m.request.startsWith(`${projectConfig.cacheDir}/data`),
name: false,
chunks: 'all',
maxSize: 60000,
minSize: 5000
}
const cacheGroups = {
data: {
test: m => m.resource && m.request.startsWith(`${projectConfig.cacheDir}/data`),
name: false,
chunks: 'all',
maxSize: 60000,
minSize: 5000
}
})
}

if (projectConfig.css.split !== true) {
cacheGroups.styles = {
name: 'styles',
test: m => /css\/mini-extract/.test(m.type),
chunks: 'all',
enforce: true
}
}

config.optimization.splitChunks({ cacheGroups })
}

if (process.env.GRIDSOME_TEST) {
Expand Down
4 changes: 2 additions & 2 deletions gridsome/lib/webpack/plugins/VueSSRClientPlugin.js
Expand Up @@ -32,14 +32,14 @@ VueSSRClientPlugin.prototype.apply = function apply (compiler) {
var allFiles = uniq(stats.assets
.map(function (a) { return a.name }))
// Avoid preloading / injecting the style chunk
.filter(file => !/styles\.\w{8}\.js$/.test(file))
.filter(file => !/styles(\.\w{8})?\.js$/.test(file))

var initialFiles = uniq(Object.keys(stats.entrypoints)
.map(function (name) { return stats.entrypoints[name].assets })
.reduce(function (assets, all) { return all.concat(assets) }, [])
.filter(function (file) { return isJS(file) || isCSS(file) }))
// Avoid preloading / injecting the style chunk
.filter(file => !/styles\.\w{8}\.js$/.test(file))
.filter(file => !/styles(\.\w{8})?\.js$/.test(file))

var asyncFiles = allFiles
.filter(function (file) { return isJS(file) || isCSS(file) })
Expand Down

0 comments on commit 952148d

Please sign in to comment.