UNPKG

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