Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 10 additions & 70 deletions lib/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ const _ = require('lodash'),
url = require('url'),
STYLE_TAG = 'style',
SCRIPT_TAG = 'scripts',
ASYNC_SCRIPT_TAG = 'async',
DEFER_SCRIPT_TAG = 'defer',
ASYNC_DEFER_SCRIPT_TAG = 'async-defer',
MEDIA_DIRECTORY = path.join(process.cwd(), 'public');

/**
Expand Down Expand Up @@ -156,43 +153,12 @@ function injectTags(fileArray, site, tag) {
return bluebird.resolve(_.map(fileArray, function (file) {
if (tag === STYLE_TAG) {
return `<link rel="stylesheet" type="text/css" href="${file}${buster}">`;
} else if (tag === ASYNC_SCRIPT_TAG) {
return `<script async src="${file}" type="text/javascript"></script>`;
} else if (tag === DEFER_SCRIPT_TAG) {
return `<script defer src="${file}" type="text/javascript"></script>`;
} else if (tag === ASYNC_DEFER_SCRIPT_TAG) {
return `<script async defer src="${file}" type="text/javascript"></script>`;
} else {
return `<script type="text/javascript" src="${file}${buster}"></script>`;
}
}).join('\n'));
}

/**
* Filter the components rendered in this request, removing Webpack-managed
* assets so that we can fall back on Browserify.
*
* @param {Object} state - Amphora render state.
* @returns {string[]} - A list of components not available through Webpack.
*/
function filterManifestComponents(state) {
const site = state.locals.site,
assetDir = site && site.assetDir || MEDIA_DIRECTORY,
manifestName = site && site.manifestName || 'assets-manifest.json',
manifestFile = path.resolve(path.join(assetDir, manifestName));
let manifest;

try {
manifest = files.tryRequire(manifestFile);
} catch (err) {
return state._components;
}


return state._components
.filter(componentName => !manifest.hasOwnProperty(`${ componentName }.js`));
}

/**
* Gets a list of all css and js needed for the components listed.
* @param {Object} state
Expand All @@ -202,7 +168,6 @@ function getMediaMap(state) {
return {
styles: module.exports.getStyleFiles(state),
scripts: module.exports.getScriptFiles(state),
manifestAssets: module.exports.getManifestAssets(state)
};
}

Expand Down Expand Up @@ -274,6 +239,14 @@ function getStyleFiles(state) {
}
}

// check for clay compile linked? clay compile font files?
const defaultFontPath = path.join(assetDir, 'css', '_linked-fonts._default.css');
const siteFontPath = path.join(assetDir, 'css', `_linked-fonts.${siteStyleguide}.css`);

// add any default and site font css
cssFilePaths.push(defaultFontPath);
cssFilePaths.push(siteFontPath);

return cssFilePaths
.filter(files.fileExists)
.map(pathJoin(assetHost, assetPath, assetDir));
Expand All @@ -295,7 +268,7 @@ function getScriptFiles(state) {
assetPath = site && site.assetPath || '',
assetHost = site && site.assetHost || '';

return filterManifestComponents(state)
return state._components
.reduce((prev, name) => {
prev.push(
path.join(assetDir, 'js', `${name}.js`),
Expand All @@ -308,36 +281,6 @@ function getScriptFiles(state) {
.map(pathJoin(assetHost, assetPath, assetDir));
}

/**
* Read the asset manifest generated by the `clay pack` bundling command and
* check for scripts which match the rendered component names. The manifest for
* each asset lists its complete set of dependencies, so we dedupe them.
* Webpack's runtime is added to the beginning of the list, downstream legacy
* globals and Clay CLI's init script to the end.
*
* @param {Object} state - Amphora's render state.
* @return {string[]} A list of component assets.
*/
function getManifestAssets(state) {
const site = state.locals.site,
assetDir = site && site.assetDir || MEDIA_DIRECTORY,
assetHost = site && site.assetHost || '/',
manifestName = site && site.manifestName || 'assets-manifest.json',
manifestFile = path.resolve(path.join(assetDir, manifestName));
let manifest;

try {
manifest = files.tryRequire(manifestFile);
} catch (err) {
return [];
}

const entrypoints = _.get(manifest, 'entrypoints', []);
const scriptFiles = _.flatMap(entrypoints, entrypoint => _.get(entrypoint, 'assets.js', []));

return scriptFiles.map(script => url.resolve(assetHost, script));
}

/**
* Trim the path on the file system bythe link of the
* asset directory and then join it with either the assetHost
Expand Down Expand Up @@ -408,9 +351,7 @@ function injectScriptsAndStyles(state) {

if (!locals.edit) {
mediaMap.styles = combineFileContents(mediaMap.styles, 'public/css', '/css/', STYLE_TAG);
mediaMap.scripts = !!mediaMap.manifestAssets && mediaMap.manifestAssets.length > 0
? injectTags(mediaMap.manifestAssets, locals.site, SCRIPT_TAG)
: combineFileContents(mediaMap.scripts, 'public/js', '/js/', SCRIPT_TAG);
mediaMap.scripts = combineFileContents(mediaMap.scripts, 'public/js', '/js/', SCRIPT_TAG);
} else {
mediaMap.styles = module.exports.editStylesTags ? injectTags(mediaMap.styles, locals.site, STYLE_TAG) : combineFileContents(mediaMap.styles, 'public/css', '/css/', STYLE_TAG);
mediaMap.scripts = module.exports.editScriptsTags ? injectTags(mediaMap.scripts, locals.site, SCRIPT_TAG) : combineFileContents(mediaMap.scripts, 'public/js', '/js/', SCRIPT_TAG);
Expand All @@ -433,6 +374,5 @@ module.exports.editStylesTags = false;
module.exports.editScriptsTags = false;

// For testing
module.exports.getManifestAssets = getManifestAssets;
module.exports.getScriptFiles = getScriptFiles;
module.exports.getStyleFiles = getStyleFiles;
119 changes: 4 additions & 115 deletions lib/media.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ describe(_.startCase(filename), () => {
const fn = lib['getMediaMap'];

test('accepts state with empty components', () => {
expect(fn(state)).toEqual({manifestAssets: [], scripts: [], styles: []});
expect(fn(state)).toEqual({scripts: [], styles: []});
});

test('accepts list, empty slug (non-existent components)', () => {
Expand All @@ -114,7 +114,7 @@ describe(_.startCase(filename), () => {
_.omit(state, ['locals.site.slug'])
)
)
).toEqual({manifestAssets: [], scripts: [], styles: []});
).toEqual({scripts: [], styles: []});
});

test('accepts list and slug (non-existent components)', () => {
Expand All @@ -127,7 +127,7 @@ describe(_.startCase(filename), () => {
state
)
)
).toEqual({manifestAssets: [], scripts: [], styles: []});
).toEqual({scripts: [], styles: []});
});

test(
Expand All @@ -151,7 +151,7 @@ describe(_.startCase(filename), () => {
}
)
)
).toEqual({manifestAssets: [], scripts: expectedScriptFiles, styles: []});
).toEqual({scripts: expectedScriptFiles, styles: []});
}
);
});
Expand Down Expand Up @@ -625,117 +625,6 @@ describe(_.startCase(filename), () => {
);
});

describe('getManifestAssets', () => {
const fn = lib['getManifestAssets'];

describe('constructs the correct asset URL', () => {
test('when assetHost is configured', () => {
const assetHost = 'https://assets.nymag.com';
const localState = {
locals: {
site: {
assetHost
}
},
_components: [
'a',
'b'
]
};
const manifest = {
entrypoints: {
a: {
assets: {
js: ['/a.js']
}
},
b: {
assets: {
js: ['b.js']
}
}
}
};

jest.spyOn(files, 'tryRequire').mockImplementation(() => manifest);

expect(fn(localState)).toEqual([
`${ assetHost }/a.js`,
`${ assetHost }/b.js`
]);
});

test('when assetHost is not configured', () => {
const localState = {
locals: {
site: {
}
},
_components: [
'a',
'b'
]
};
const manifest = {
entrypoints: {
a: {
assets: {
js: ['/a.js']
}
},
b: {
assets: {
js: ['b.js']
}
}
}
};

jest.spyOn(files, 'tryRequire').mockImplementation(() => manifest);

expect(fn(localState)).toEqual([
'/a.js',
'/b.js'
]);
});

test('without prepending assetPath', () => {
const localState = {
locals: {
site: {
assetPath: '/strategist'
}
},
_components: [
'a',
'b'
]
};
const manifest = {
entrypoints: {
a: {
assets: {
js: ['/a.js']
}
},
b: {
assets: {
js: ['b.js']
}
}
}
};

jest.spyOn(files, 'tryRequire').mockImplementation(() => manifest);

expect(fn(localState)).toEqual([
'/a.js',
'/b.js'
]);
});
});
});

describe('injectScriptsAndStyles', () => {
const fn = lib['injectScriptsAndStyles'];

Expand Down
6 changes: 3 additions & 3 deletions lib/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function applyRenderHooks(ref, data, locals) {
* @param {Object} locals
* @returns {Function}
*/
function applyPostRenderHooks(ref, locals) {
function applyPostRenderHooks(ref, locals, res, self) {
return (html) => {

// skip postRender hooks in edit mode
Expand All @@ -50,7 +50,7 @@ function applyPostRenderHooks(ref, locals) {

return setup.plugins.filter((plugin) => plugin.postRender)
.reduce((val, plugin) => {
return plugin.postRender(ref, html, locals);
return plugin.postRender(ref, html, locals, res, self);
}, html);
};
}
Expand Down Expand Up @@ -148,7 +148,7 @@ function render(data, meta, res) {
return applyRenderHooks(state._layoutRef || state.self, data, state.locals)
.then(makeHtml(state))
.then(mediaService.injectScriptsAndStyles(state))
.then(applyPostRenderHooks(state._layoutRef || state.self, state.locals))
.then(applyPostRenderHooks(state._layoutRef || state.self, state.locals, res, meta._ref))
.then(result => {
res.type('text/html');
res.send(result);
Expand Down
Loading
Loading