1 | var assertHtml = require('assert-html')
|
2 | var dedent = require('dedent')
|
3 | var mkdirp = require('mkdirp')
|
4 | var path = require('path')
|
5 | var tape = require('tape')
|
6 | var tmp = require('tmp')
|
7 | var fs = require('fs')
|
8 |
|
9 | var bankai = require('../')
|
10 |
|
11 | tape('renders some HTML', function (assert) {
|
12 | var expected = `
|
13 | <!DOCTYPE html>
|
14 | <html lang="en-US" dir="ltr">
|
15 | <head>
|
16 | <meta charset="utf-8">
|
17 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
18 | <script src="/__SCRIPTS_HASH__/bundle.js" integrity="sha512-__SCRIPTS_INTEGRITY__" defer></script>
|
19 | <script>;(function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b})("undefined"!=typeof global?global:this);;(function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}})(this);</script>
|
20 | <link rel="manifest" href="/manifest.json">
|
21 | <meta name="description" content=>
|
22 | <meta name="theme-color" content=#fff>
|
23 | <title></title>
|
24 | <link rel="preload" as="style" href="/__STYLE_HASH__/bundle.css" onload="this.rel='stylesheet'">
|
25 | </head>
|
26 | <body></body>
|
27 | </html>
|
28 | `.replace(/\n +/g, '')
|
29 |
|
30 | var script = dedent`
|
31 | 1 + 1
|
32 | `
|
33 |
|
34 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
35 | assert.on('end', tmpDir.removeCallback)
|
36 | var tmpScriptname = path.join(tmpDir.name, 'index.js')
|
37 |
|
38 | mkdirp.sync(tmpDir.name)
|
39 | fs.writeFileSync(tmpScriptname, script)
|
40 |
|
41 | var compiler = bankai(tmpScriptname, { watch: false })
|
42 | compiler.documents('/', function (err, res) {
|
43 | assert.error(err, 'no error writing document')
|
44 | assertHtml(assert, String(res.buffer), expected)
|
45 | })
|
46 |
|
47 | compiler.on('change', function (nodeName, second) {
|
48 | if (nodeName !== 'documents' || second !== 'list') return
|
49 | assert.end()
|
50 | })
|
51 |
|
52 | compiler.on('error', function () {
|
53 |
|
54 | })
|
55 |
|
56 | compiler.scripts('bundle.js', function (err, res) {
|
57 | assert.ifError(err, 'no err bundling scripts')
|
58 | expected = expected.replace('__SCRIPTS_HASH__', res.hash.toString('hex').slice(0, 16))
|
59 | expected = expected.replace('__SCRIPTS_INTEGRITY__', res.hash.toString('base64'))
|
60 |
|
61 | compiler.styles('bundle.css', function (err, res) {
|
62 | assert.ifError(err, 'no err bundling style')
|
63 | expected = expected.replace('__STYLE_HASH__', res.hash.toString('hex').slice(0, 16))
|
64 | expected = expected.replace('__STYLE_INTEGRITY__', res.hash.toString('base64'))
|
65 | })
|
66 | })
|
67 | })
|
68 |
|
69 | tape('server render choo apps', function (assert) {
|
70 | var expected = `
|
71 | <!DOCTYPE html>
|
72 | <html lang="en-US" dir="ltr">
|
73 | <head>
|
74 | <meta charset="utf-8">
|
75 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
76 | <script src="/__SCRIPTS_HASH__/bundle.js" integrity="sha512-__SCRIPTS_INTEGRITY__" defer></script>
|
77 | <script>;(function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b})("undefined"!=typeof global?global:this);;(function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}})(this);</script>
|
78 | <link rel="preload" as="font" crossorigin href="/assets/font.woff">
|
79 | <link rel="manifest" href="/manifest.json">
|
80 | <meta name="description" content=>
|
81 | <meta name="theme-color" content=#fff>
|
82 | <title></title>
|
83 | <link rel="preload" as="style" href="/__STYLE_HASH__/bundle.css" onload="this.rel='stylesheet'">
|
84 | </head>
|
85 | <body>
|
86 | meow
|
87 | </body>
|
88 | </html>
|
89 | `.replace(/\n +/g, '')
|
90 |
|
91 | var script = dedent`
|
92 | var html = require('choo/html')
|
93 | var choo = require('choo')
|
94 |
|
95 | var app = choo()
|
96 | app.route('/', function () {
|
97 | return html\`<body>meow</body>\`
|
98 | })
|
99 | if (module.parent) module.exports = app
|
100 | else app.mount('body')
|
101 | `
|
102 |
|
103 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
104 | assert.on('end', tmpDir.removeCallback)
|
105 | var tmpScriptname = path.join(tmpDir.name, 'index.js')
|
106 | var assetDirname = path.join(tmpDir.name, 'assets')
|
107 | var fontFilename = path.join(assetDirname, 'font.woff')
|
108 |
|
109 | mkdirp.sync(assetDirname)
|
110 |
|
111 | fs.writeFileSync(tmpScriptname, script)
|
112 | fs.writeFileSync(fontFilename, 'binary font data')
|
113 |
|
114 | var compiler = bankai(tmpScriptname, { watch: false })
|
115 | compiler.documents('/', function (err, res) {
|
116 | assert.error(err, 'no error writing document')
|
117 | assertHtml(assert, String(res.buffer), expected)
|
118 | })
|
119 |
|
120 | compiler.on('change', function (nodeName, second) {
|
121 | if (nodeName !== 'documents' || second !== 'list') return
|
122 | assert.end()
|
123 | })
|
124 |
|
125 | compiler.on('error', function () {
|
126 |
|
127 | })
|
128 |
|
129 | compiler.scripts('bundle.js', function (err, res) {
|
130 | assert.ifError(err, 'no err bundling scripts')
|
131 | expected = expected.replace('__SCRIPTS_HASH__', res.hash.toString('hex').slice(0, 16))
|
132 | expected = expected.replace('__SCRIPTS_INTEGRITY__', res.hash.toString('base64'))
|
133 | compiler.styles('bundle.css', function (err, res) {
|
134 | assert.ifError(err, 'no err bundling style')
|
135 | assert.ifError(err)
|
136 | expected = expected.replace('__STYLE_HASH__', res.hash.toString('hex').slice(0, 16))
|
137 | expected = expected.replace('__STYLE_INTEGRITY__', res.hash.toString('base64'))
|
138 | })
|
139 | })
|
140 | })
|
141 |
|
142 | tape('server render choo apps with root set', function (assert) {
|
143 | var expected = `
|
144 | <!DOCTYPE html>
|
145 | <html lang="en-US" dir="ltr">
|
146 | <head>
|
147 | <meta charset="utf-8">
|
148 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
149 | <script src="some-custom-root/__SCRIPTS_HASH__/bundle.js" integrity="sha512-__SCRIPTS_INTEGRITY__" defer></script>
|
150 | <script>;(function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b})("undefined"!=typeof global?global:this);;(function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}})(this);</script>
|
151 | <link rel="preload" as="font" crossorigin href="some-custom-root/assets/font.woff">
|
152 | <link rel="manifest" href="some-custom-root/manifest.json">
|
153 | <meta name="description" content=>
|
154 | <meta name="theme-color" content=#fff>
|
155 | <title></title>
|
156 | <link rel="preload" as="style" href="some-custom-root/__STYLE_HASH__/bundle.css" onload="this.rel='stylesheet'">
|
157 | </head>
|
158 | <body>
|
159 | meow
|
160 | </body>
|
161 | </html>
|
162 | `.replace(/\n +/g, '')
|
163 |
|
164 | var script = dedent`
|
165 | var html = require('choo/html')
|
166 | var choo = require('choo')
|
167 |
|
168 | var app = choo()
|
169 | app.route('/', function () {
|
170 | return html\`<body>meow</body>\`
|
171 | })
|
172 | if (module.parent) module.exports = app
|
173 | else app.mount('body')
|
174 | `
|
175 |
|
176 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
177 | assert.on('end', tmpDir.removeCallback)
|
178 | var tmpScriptname = path.join(tmpDir.name, 'index.js')
|
179 | var assetDirname = path.join(tmpDir.name, 'assets')
|
180 | var fontFilename = path.join(assetDirname, 'font.woff')
|
181 |
|
182 | mkdirp.sync(assetDirname)
|
183 |
|
184 | fs.writeFileSync(tmpScriptname, script)
|
185 | fs.writeFileSync(fontFilename, 'binary font data')
|
186 |
|
187 | var compiler = bankai(tmpScriptname, { watch: false, base: 'some-custom-root' })
|
188 | compiler.documents('/', function (err, res) {
|
189 | assert.error(err, 'no error writing document')
|
190 | assertHtml(assert, String(res.buffer), expected)
|
191 | })
|
192 |
|
193 | compiler.on('change', function (nodeName, second) {
|
194 | if (nodeName !== 'documents' || second !== 'list') return
|
195 | assert.end()
|
196 | })
|
197 |
|
198 | compiler.on('error', function () {
|
199 |
|
200 | })
|
201 |
|
202 | compiler.scripts('bundle.js', function (err, res) {
|
203 | assert.ifError(err, 'no err bundling scripts')
|
204 | expected = expected.replace('__SCRIPTS_HASH__', res.hash.toString('hex').slice(0, 16))
|
205 | expected = expected.replace('__SCRIPTS_INTEGRITY__', res.hash.toString('base64'))
|
206 | compiler.styles('bundle.css', function (err, res) {
|
207 | assert.ifError(err, 'no err bundling style')
|
208 | assert.ifError(err)
|
209 | expected = expected.replace('__STYLE_HASH__', res.hash.toString('hex').slice(0, 16))
|
210 | expected = expected.replace('__STYLE_INTEGRITY__', res.hash.toString('base64'))
|
211 | })
|
212 | })
|
213 | })
|
214 |
|
215 | tape('custom index.html template', function (assert) {
|
216 | assert.plan(3)
|
217 |
|
218 | var template = `
|
219 | <html>
|
220 | <head>
|
221 | <meta name="test" content="ok">
|
222 | </head>
|
223 | <body>
|
224 | </body>
|
225 | </html>
|
226 | `
|
227 | var file = `
|
228 | var html = require('choo/html')
|
229 | var choo = require('choo')
|
230 |
|
231 | var app = choo()
|
232 | app.route('/', function () {
|
233 | return html\`<body>meow</body>\`
|
234 | })
|
235 | module.exports = app.mount('body')
|
236 | `
|
237 |
|
238 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
239 | assert.on('end', tmpDir.removeCallback)
|
240 | fs.writeFileSync(path.join(tmpDir.name, 'index.js'), file)
|
241 | fs.writeFileSync(path.join(tmpDir.name, 'index.html'), template)
|
242 |
|
243 | var compiler = bankai(tmpDir.name, { watch: false })
|
244 | compiler.documents('/', function (err, res) {
|
245 | assert.error(err, 'no error writing document')
|
246 | var body = res.buffer.toString('utf8')
|
247 | assert.notEqual(body.indexOf('<meta name="test" content="ok">'), -1, 'used the custom index.html')
|
248 | assert.notEqual(body.indexOf('meow'), -1, 'inserted the rendered app')
|
249 | })
|
250 | })
|
251 |
|
252 | tape('mount choo app into given selector', function (assert) {
|
253 | assert.plan(3)
|
254 |
|
255 | var template = `
|
256 | <html>
|
257 | <head></head>
|
258 | <body>
|
259 | <h1>Some Title!</h1>
|
260 | <div id="app"></div>
|
261 | </body>
|
262 | </html>
|
263 | `
|
264 | var file = `
|
265 | var html = require('choo/html')
|
266 | var choo = require('choo')
|
267 |
|
268 | var app = choo()
|
269 | app.route('/', function () {
|
270 | return html\`<div>meow</div>\`
|
271 | })
|
272 | module.exports = app.mount('#app')
|
273 | `
|
274 |
|
275 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
276 | assert.on('end', tmpDir.removeCallback)
|
277 | fs.writeFileSync(path.join(tmpDir.name, 'index.js'), file)
|
278 | fs.writeFileSync(path.join(tmpDir.name, 'index.html'), template)
|
279 |
|
280 | var compiler = bankai(tmpDir.name, { watch: false })
|
281 | compiler.documents('/', function (err, res) {
|
282 | assert.error(err, 'no error writing document')
|
283 | var body = res.buffer.toString('utf8')
|
284 | assert.notEqual(body.indexOf('<h1>Some Title!</h1>'), -1, 'preserved body contents outside #app selector')
|
285 | assert.notEqual(body.indexOf('meow'), -1, 'inserted the rendered app')
|
286 | })
|
287 | })
|
288 |
|
289 | tape('inlines critical css', function (assert) {
|
290 | assert.plan(3)
|
291 |
|
292 | var file = `
|
293 | var css = require('sheetify')
|
294 | var html = require('choo/html')
|
295 | var choo = require('choo')
|
296 |
|
297 | css\`
|
298 | .classA { color: red }
|
299 | .classB { color: blue }
|
300 | \`
|
301 |
|
302 | var app = choo()
|
303 | app.route('/', function () {
|
304 | return html\`<body class="classA"></body>\`
|
305 | })
|
306 |
|
307 | // classB
|
308 |
|
309 | module.exports = app.mount('body')
|
310 | `
|
311 |
|
312 | var tmpDir = tmp.dirSync({ dir: path.join(__dirname, '../tmp'), unsafeCleanup: true })
|
313 | assert.on('end', tmpDir.removeCallback)
|
314 | fs.writeFileSync(path.join(tmpDir.name, 'index.js'), file)
|
315 |
|
316 | var compiler = bankai(tmpDir.name, { watch: false })
|
317 | compiler.documents('/', function (err, res) {
|
318 | assert.error(err, 'no error writing document')
|
319 | var body = res.buffer.toString('utf8')
|
320 | assert.notEqual(body.indexOf('.classA{color:red;}'), -1, 'inlined the .classA selector')
|
321 | assert.equal(body.indexOf('.classB{color:blue;}'), -1, 'did not inline the .classB selector')
|
322 | })
|
323 | })
|