Skip to content
This repository has been archived by the owner on Aug 5, 2020. It is now read-only.

Commit

Permalink
Set up ability to inline CSS into server response. (#1194)
Browse files Browse the repository at this point in the history
* Set up ability to inline CSS into server response.

Save a round trip. Makes a big difference.

* Declare global instead of suppressing Flow

* Fix CSS inlining when using custom ASSET_URL.

* Use correct publicPath.

* Add additional information in ChunksPlugin.

The name of the chunk can be read in linkAssets, which avoids any
string replacement of public path. Much safer.

* No more [object Object]

* Tests, bug fixes, and code cleanup.
  • Loading branch information
threehams committed May 23, 2018
1 parent b9a8977 commit 619e8cc
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 172 deletions.
1 change: 1 addition & 0 deletions flow/application-config.js.flow
Expand Up @@ -33,6 +33,7 @@ declare module 'application-config' {
changed: string[],
},
enableErrorOverlay: boolean,
inlineAllCss: boolean,
[key: string]: any,
};

Expand Down
4 changes: 4 additions & 0 deletions packages/gluestick/src/__tests__/mocks/context.js
Expand Up @@ -58,11 +58,15 @@ const gsConfig: GSConfig = {
changed: [],
},
enableErrorOverlay: true,
inlineAllCss: false,
};

const client: WebpackConfig = {
resolve: {},
module: {},
output: {
publicPath: '/assets',
},
};
const server: WebpackConfig = {};

Expand Down
1 change: 1 addition & 0 deletions packages/gluestick/src/config/defaults/glueStickConfig.js
Expand Up @@ -64,6 +64,7 @@ const config: GSConfig = {
],
},
enableErrorOverlay: true,
inlineAllCss: false,
};

module.exports = config;
31 changes: 11 additions & 20 deletions packages/gluestick/src/config/webpack/ChunksPlugin.js
@@ -1,19 +1,10 @@
/* @flow */
import type { WebpackConfig } from '../../types';
import type { ChunksInfo, ChunkInfo, WebpackConfig } from '../../types';

const path = require('path');
const fs = require('fs');
const mkdir = require('mkdirp');

type ChunksInfo = {
javascript: {
[key: ?string]: string,
},
styles: {
[key: ?string]: string,
},
};

const chunkInfoFilePath = (
webpackConfiguration: WebpackConfig,
chunkInfoFilename?: string = 'webpack-chunks.json',
Expand All @@ -22,17 +13,17 @@ const chunkInfoFilePath = (
return path.join(webpackConfiguration.output.path, chunkInfoFilename);
};

const getChunksInfoBody = (json: Object, publicPath: string): ChunksInfo => {
const assetsByChunk: Object = json.assetsByChunkName;
const getChunksInfoBody = (stats: Object, publicPath: string): ChunksInfo => {
const assetsByChunk = stats.assetsByChunkName;

const assetsChunks: ChunksInfo = {
javascript: {},
styles: {},
};

// gets asset paths by name and extension of their chunk
const getAssets = (chunkName: string, extension: string): string[] => {
let chunk: string | string[] = json.assetsByChunkName[chunkName];
const getAssets = (chunkName: string, extension: string): ChunkInfo[] => {
let chunk: string | string[] = stats.assetsByChunkName[chunkName];

// a chunk could be a string or an array, so make sure it is an array
if (!Array.isArray(chunk)) {
Expand All @@ -41,18 +32,18 @@ const getChunksInfoBody = (json: Object, publicPath: string): ChunksInfo => {

return chunk
.filter(name => path.extname(name) === `.${extension}`)
.map(name => `${publicPath}${name}`);
.map(name => ({ url: `${publicPath}${name}`, name }));
};

Object.keys(assetsByChunk).forEach((name: string) => {
// The second asset is usually a source map
const jsAsset: string = getAssets(name, 'js')[0];
const jsAsset = getAssets(name, 'js')[0];

if (jsAsset) {
assetsChunks.javascript[name] = jsAsset;
}

const styleAsset: string = getAssets(name, 'css')[0];
const styleAsset = getAssets(name, 'css')[0];

if (styleAsset) {
assetsChunks.styles[name] = styleAsset;
Expand All @@ -77,18 +68,18 @@ module.exports = class ChunksPlugin {
}

apply(compiler: Object): void {
const outputFilePath: string = chunkInfoFilePath(
const outputFilePath = chunkInfoFilePath(
this.configuration,
this.options.chunkInfoFilename,
);

compiler.plugin('done', (stats: Object) => {
const json: Object = stats.toJson({
const json = stats.toJson({
context: this.configuration.context || process.cwd(),
chunkModules: true,
});

const publicPath: string =
const publicPath =
process.env.NODE_ENV !== 'production' &&
this.configuration.devServer &&
typeof this.configuration.devServer.publicPath === 'string'
Expand Down
Expand Up @@ -4,11 +4,11 @@ jest.mock(
'path/webpack-chunks',
() => ({
javascript: {
main: 'publicPath/main.js',
profile: 'publicPath/profile.js',
main: { name: 'main.js', url: 'publicPath/main.js' },
profile: { name: 'profile.js', url: 'publicPath/profile.js' },
},
styles: {
main: 'publicPath/main.css',
main: { name: 'main.css', url: 'publicPath/main.css' },
},
}),
{ virtual: true },
Expand All @@ -34,11 +34,11 @@ describe('ChunksPlugin', () => {
});
expect(JSON.parse(fs.readFileSync('path/webpack-chunks.json'))).toEqual({
javascript: {
main: 'publicPath/main.js',
profile: 'publicPath/profile.js',
main: { name: 'main.js', url: 'publicPath/main.js' },
profile: { name: 'profile.js', url: 'publicPath/profile.js' },
},
styles: {
main: 'publicPath/main.css',
main: { name: 'main.css', url: 'publicPath/main.css' },
},
});
fs.unlinkSync('path/webpack-chunks.json');
Expand All @@ -63,13 +63,13 @@ describe('ChunksPlugin', () => {
});
expect(JSON.parse(fs.readFileSync('path/webpack-chunks'))).toEqual({
javascript: {
main: 'publicPath/main.js',
profile: 'publicPath/profile.js',
home: 'publicPath/home.js',
main: { name: 'main.js', url: 'publicPath/main.js' },
profile: { name: 'profile.js', url: 'publicPath/profile.js' },
home: { name: 'home.js', url: 'publicPath/home.js' },
},
styles: {
main: 'publicPath/main.css',
home: 'publicPath/home.css',
main: { name: 'main.css', url: 'publicPath/main.css' },
home: { name: 'home.css', url: 'publicPath/home.css' },
},
});
fs.unlinkSync('path/webpack-chunks.json');
Expand Down
4 changes: 2 additions & 2 deletions packages/gluestick/src/renderer/__tests__/render.test.js
Expand Up @@ -180,7 +180,7 @@ describe('renderer/render', () => {
};
};

it('should prepare plugins and pass it to EntryWrapper', () => {
it('should prepare plugins and pass it to EntryWrapper', async () => {
const entriesRuntimePlugins = [
{ name: 'plugin1', body: v => v, meta: { wrapper: true } },
{ name: 'plugin2', body: () => {}, meta: {} },
Expand All @@ -199,7 +199,7 @@ describe('renderer/render', () => {
const currentRoute = clone(renderProps);
currentRoute.email = false;
currentRoute.cache = false;
render(
await render(
context,
request,
{
Expand Down

0 comments on commit 619e8cc

Please sign in to comment.