UNPKG

14.7 kBJavaScriptView Raw
1var assertHtml = require('assert-html')
2var dedent = require('dedent')
3var mkdirp = require('mkdirp')
4var path = require('path')
5var tape = require('tape')
6var tmp = require('tmp')
7var fs = require('fs')
8
9var bankai = require('../')
10
11tape('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 // assert.error(err, 'no error')
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
69tape('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 // assert.error(err, 'no error')
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
142tape('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 // assert.error(err, 'no error')
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
215tape('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
252tape('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
289tape('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})