Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support <meteor-bundled-css /> pseudo-tag for controlling position of CSS bundle. (#24) #9657

Merged
merged 13 commits into from
Feb 21, 2018
7 changes: 7 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
[Issue 9639](https://github.com/meteor/meteor/issues/9639)
[PR #9663](https://github.com/meteor/meteor/pull/9663)

* If the new pseudo tag `<meteor-bundled-css />` is used anywhere in the
`<head />` of an app, it will be replaced by the `link` to Meteor's bundled
CSS. If the new tag isn't used, the bundle will be placed at the top of
the `<head />` section as before (for backwards compatibility).
[FR #24](https://github.com/meteor/meteor/pull/24)
[PR #9657](https://github.com/meteor/meteor/pull/9657)

## v1.6.1, 2018-01-19

* Node has been updated to version
Expand Down
2 changes: 1 addition & 1 deletion packages/boilerplate-generator-tests/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Package.describe({
// These tests are in a separate package so that we can Npm.depend on
// parse5, a html parsing library.
summary: "Tests for the boilerplate-generator package",
version: '1.4.0',
version: '1.4.1',
documentation: null
});

Expand Down
8 changes: 6 additions & 2 deletions packages/boilerplate-generator-tests/test-lib.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import streamToString from "stream-to-string";

export async function generateHTMLForArch(arch) {
export async function generateHTMLForArch(arch, includeHead) {
// Use a dummy manifest. None of these paths will be read from the filesystem, but css / js should be handled differently
const manifest = [
{
Expand Down Expand Up @@ -34,6 +34,9 @@ export async function generateHTMLForArch(arch) {
foo: 'foobar',
gems: '&"',
};
const head = includeHead
? '<meta name="1" content="">\n<meteor-bundled-css>\n<meta name="2" content="">\n'
: '';

// A dummy rewrite hook to test ampersands
function bundledJsCssUrlRewriteHook(url) {
Expand All @@ -48,7 +51,8 @@ export async function generateHTMLForArch(arch) {
rootUrlPathPrefix,
bundledJsCssUrlRewriteHook,
inlineScriptsAllowed,
inline
inline,
head
},
});

Expand Down
26 changes: 24 additions & 2 deletions packages/boilerplate-generator-tests/web.browser-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { _ } from 'meteor/underscore';
Tinytest.addAsync(
"boilerplate-generator-tests - web.browser - basic output",
async function (test) {
const html = await generateHTMLForArch("web.browser");
const html = await generateHTMLForArch("web.browser", false);

// well-formed html
const formatted = serialize(parse(html));
Expand Down Expand Up @@ -37,12 +37,34 @@ Tinytest.addAsync(
}
);

// https://github.com/meteor/meteor-feature-requests/issues/24
Tinytest.addAsync(
"boilerplate-generator-tests - web.browser - meteor-bundled-css",
async function (test) {
const html = await generateHTMLForArch("web.browser", true);

// include CSS
test.matches(html, /<link[^<>]*href="[^<>]*bootstrap[^<>]*">/, "include CSS");

// css in correct location
const meta1 = html.search(/<meta name="1"[^<>]*>/);
const meta2 = html.search(/<meta name="2"[^<>]*>/);
const css = html.search(/<link[^<>]*href="[^<>]*bootstrap[^<>]*">/);

// CSS is after meta1
test.isTrue(meta1 < css, "CSS is NOT after meta1");

// CSS is before meta2
test.isTrue(css < meta2, "CSS is NOT before meta2");
}
);

// https://github.com/meteor/meteor/issues/9149
Tinytest.addAsync(
"boilerplate-generator-tests - web.browser - properly render boilerplate " +
"elements when _.template settings are overridden",
async function (test) {
const newHtml = await generateHTMLForArch("web.browser");
const newHtml = await generateHTMLForArch("web.browser", false);

_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
Expand Down
26 changes: 24 additions & 2 deletions packages/boilerplate-generator-tests/web.cordova-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { _ } from 'meteor/underscore';
Tinytest.addAsync(
"boilerplate-generator-tests - web.cordova - basic output",
async function (test) {
const html = await generateHTMLForArch("web.cordova");
const html = await generateHTMLForArch("web.cordova", false);

// well-formed html
const formatted = serialize(parse(html));
Expand All @@ -31,12 +31,34 @@ Tinytest.addAsync(
}
);

// https://github.com/meteor/meteor-feature-requests/issues/24
Tinytest.addAsync(
"boilerplate-generator-tests - web.cordova - meteor-bundled-css",
async function (test) {
const html = await generateHTMLForArch("web.browser", true);

// include CSS
test.matches(html, /<link[^<>]*href="[^<>]*bootstrap[^<>]*">/, "include CSS");

// css in correct location
const meta1 = html.search(/<meta name="1"[^<>]*>/);
const meta2 = html.search(/<meta name="2"[^<>]*>/);
const css = html.search(/<link[^<>]*href="[^<>]*bootstrap[^<>]*">/);

// CSS is after meta1
test.isTrue(meta1 < css, "CSS is NOT after meta1");

// CSS is before meta2
test.isTrue(css < meta2, "CSS is NOT before meta2");
}
);

// https://github.com/meteor/meteor/issues/9149
Tinytest.addAsync(
"boilerplate-generator-tests - web.cordova - properly render boilerplate " +
"elements when _.template settings are overridden",
async function (test) {
const newHtml = await generateHTMLForArch('web.cordova');
const newHtml = await generateHTMLForArch('web.cordova', false);

_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
Expand Down
2 changes: 1 addition & 1 deletion packages/boilerplate-generator/package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
summary: "Generates the boilerplate html from program's manifest",
version: '1.4.0'
version: '1.4.1'
});

Npm.depends({
Expand Down
39 changes: 23 additions & 16 deletions packages/boilerplate-generator/template-web.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,33 @@ export const headTemplate = ({
bundledJsCssUrlRewriteHook,
head,
dynamicHead,
}) => [
'<html' + Object.keys(htmlAttributes || {}).map(
key => template(' <%= attrName %>="<%- attrValue %>"')({
attrName: key,
attrValue: htmlAttributes[key],
})
).join('') + '>',
'<head>',

...(css || []).map(file =>
}) => {
var headSections = head.split(/<meteor-bundled-css[^<>]*>/, 2);
var cssBundle = [...(css || []).map(file =>
template(' <link rel="stylesheet" type="text/css" class="__meteor-css__" href="<%- href %>">')({
href: bundledJsCssUrlRewriteHook(file.url),
})
),
)].join('\n');

head,
dynamicHead,
'</head>',
'<body>',
].join('\n');
return [
'<html' + Object.keys(htmlAttributes || {}).map(
key => template(' <%= attrName %>="<%- attrValue %>"')({
attrName: key,
attrValue: htmlAttributes[key],
})
).join('') + '>',

'<head>',

(headSections.length === 1)
? [cssBundle, headSections[0]].join('\n')
: [headSections[0], cssBundle, headSections[1]].join('\n'),

dynamicHead,
'</head>',
'<body>',
].join('\n');
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation looks like a little off here - looks like lines 21 - 35 need to be indented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire "return [" block needed to be indented. I also added a couple of blank lines to make it easier to see which lines go together.


// Template function for rendering the boilerplate html for browsers
export const closeTemplate = ({
Expand Down
106 changes: 57 additions & 49 deletions packages/boilerplate-generator/template-web.cordova.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,68 @@ export const headTemplate = ({
bundledJsCssUrlRewriteHook,
head,
dynamicHead,
}) => [
'<html>',
'<head>',
' <meta charset="utf-8">',
' <meta name="format-detection" content="telephone=no">',
' <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, viewport-fit=cover">',
' <meta name="msapplication-tap-highlight" content="no">',
' <meta http-equiv="Content-Security-Policy" content="default-src * gap: data: blob: \'unsafe-inline\' \'unsafe-eval\' ws: wss:;">',
}) => {
var headSections = head.split(/<meteor-bundled-css[^<>]*>/, 2);
var cssBundle = [
// We are explicitly not using bundledJsCssUrlRewriteHook: in cordova we serve assets up directly from disk, so rewriting the URL does not make sense
...(css || []).map(file =>
template(' <link rel="stylesheet" type="text/css" class="__meteor-css__" href="<%- href %>">')({
href: file.url,
})
)].join('\n');

// We are explicitly not using bundledJsCssUrlRewriteHook: in cordova we serve assets up directly from disk, so rewriting the URL does not make sense
...(css || []).map(file =>
template(' <link rel="stylesheet" type="text/css" class="__meteor-css__" href="<%- href %>">')({
href: file.url,
})
),
return [
'<html>',
'<head>',
' <meta charset="utf-8">',
' <meta name="format-detection" content="telephone=no">',
' <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, viewport-fit=cover">',
' <meta name="msapplication-tap-highlight" content="no">',
' <meta http-equiv="Content-Security-Policy" content="default-src * gap: data: blob: \'unsafe-inline\' \'unsafe-eval\' ws: wss:;">',

' <script type="text/javascript">',
template(' __meteor_runtime_config__ = JSON.parse(decodeURIComponent(<%= conf %>));')({
conf: meteorRuntimeConfig,
}),
' if (/Android/i.test(navigator.userAgent)) {',
// When Android app is emulated, it cannot connect to localhost,
// instead it should connect to 10.0.2.2
// (unless we\'re using an http proxy; then it works!)
' if (!__meteor_runtime_config__.httpProxyPort) {',
' __meteor_runtime_config__.ROOT_URL = (__meteor_runtime_config__.ROOT_URL || \'\').replace(/localhost/i, \'10.0.2.2\');',
' __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL = (__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL || \'\').replace(/localhost/i, \'10.0.2.2\');',
' }',
' }',
' </script>',
'',
' <script type="text/javascript" src="/cordova.js"></script>',
(headSections.length === 1)
? [cssBundle, headSections[0]].join('\n')
: [headSections[0], cssBundle, headSections[1]].join('\n'),

...(js || []).map(file =>
template(' <script type="text/javascript" src="<%- src %>"></script>')({
src: file.url,
})
),
' <script type="text/javascript">',
template(' __meteor_runtime_config__ = JSON.parse(decodeURIComponent(<%= conf %>));')({
conf: meteorRuntimeConfig,
}),
' if (/Android/i.test(navigator.userAgent)) {',
// When Android app is emulated, it cannot connect to localhost,
// instead it should connect to 10.0.2.2
// (unless we\'re using an http proxy; then it works!)
' if (!__meteor_runtime_config__.httpProxyPort) {',
' __meteor_runtime_config__.ROOT_URL = (__meteor_runtime_config__.ROOT_URL || \'\').replace(/localhost/i, \'10.0.2.2\');',
' __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL = (__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL || \'\').replace(/localhost/i, \'10.0.2.2\');',
' }',
' }',
' </script>',
'',
' <script type="text/javascript" src="/cordova.js"></script>',

...(additionalStaticJs || []).map(({ contents, pathname }) => (
inlineScriptsAllowed
? template(' <script><%= contents %></script>')({
contents,
})
: template(' <script type="text/javascript" src="<%- src %>"></script>')({
src: rootUrlPathPrefix + pathname
...(js || []).map(file =>
template(' <script type="text/javascript" src="<%- src %>"></script>')({
src: file.url,
})
)),
'',
head,
'</head>',
'',
'<body>',
].join('\n');
),

...(additionalStaticJs || []).map(({ contents, pathname }) => (
inlineScriptsAllowed
? template(' <script><%= contents %></script>')({
contents,
})
: template(' <script type="text/javascript" src="<%- src %>"></script>')({
src: rootUrlPathPrefix + pathname
})
)),
'',
head,
'</head>',
'',
'<body>',
].join('\n');
};

export function closeTemplate() {
return "</body>\n</html>";
Expand Down