diff --git a/package-lock.json b/package-lock.json index 0519ed458..108ecfc30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5439,6 +5439,11 @@ "setimmediate": "^1.0.4" } }, + "tippex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tippex/-/tippex-3.0.0.tgz", + "integrity": "sha1-sXYJonzq/+B5ezhzk/2Zh45Nfqk=" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 0249ea938..5152501ed 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "http-link-header": "^1.0.2", "shimport": "^1.0.1", "sourcemap-codec": "^1.4.6", - "string-hash": "^1.1.3" + "string-hash": "^1.1.3", + "tippex": "^3.0.0" }, "devDependencies": { "@types/mocha": "^5.2.7", diff --git a/src/core/create_manifest_data.ts b/src/core/create_manifest_data.ts index b33e7a40c..6beed040c 100644 --- a/src/core/create_manifest_data.ts +++ b/src/core/create_manifest_data.ts @@ -1,9 +1,26 @@ import * as fs from 'fs'; import * as path from 'path'; -import svelte from 'svelte/compiler'; +import * as tippex from 'tippex'; import { Page, PageComponent, ServerRoute, ManifestData } from '../interfaces'; import { posixify, reserved_words } from '../utils'; +export function template_has_preload(content: string) { + const regex = /([^]*?)<\/script>/g; + let m; + while ((m = regex.exec(content)) !== null) { + // This is necessary to avoid infinite loops with zero-width matches + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + + const source_minus_comments = tippex.erase(m[1]); + if (/export\s+.*?preload/.test(source_minus_comments)) { + return true; + } + } + return false; +} + export default function create_manifest_data(cwd: string, extensions: string = '.svelte .html'): ManifestData { const component_extensions = extensions.split(' '); @@ -13,30 +30,24 @@ export default function create_manifest_data(cwd: string, extensions: string = ' throw new Error(`As of Sapper 0.21, the routes/ directory should become src/routes/`); } - function has_preload(file: string) { - const source = fs.readFileSync(path.join(cwd, file), 'utf-8'); - - if (/preload/.test(source)) { - try { - const { vars } = svelte.compile(source.replace(/]*>[^]*?<\/style>/g, ''), { generate: false }); - return vars.some((variable: any) => variable.module && variable.export_name === 'preload'); - } catch (err) {} - } - - return false; + function file_has_preload(file: string) { + const content = fs.readFileSync(path.join(cwd, file), 'utf-8'); + return template_has_preload(content); } function find_layout(file_name: string, component_name: string, dir: string = '') { const ext = component_extensions.find((ext) => fs.existsSync(path.join(cwd, dir, `${file_name}${ext}`))); const file = posixify(path.join(dir, `${file_name}${ext}`)) - return ext - ? { + if (!ext) { + return null; + } + + return { name: component_name, file: file, - has_preload: has_preload(file) - } - : null; + has_preload: file_has_preload(file) + }; } const components: PageComponent[] = []; @@ -162,7 +173,7 @@ export default function create_manifest_data(cwd: string, extensions: string = ' const component = { name: get_slug(item.file), file: item.file, - has_preload: has_preload(item.file) + has_preload: file_has_preload(item.file) }; components.push(component); diff --git a/test/unit/create_manifest_data/test.ts b/test/unit/create_manifest_data/test.ts index 804a61be1..64d72e198 100644 --- a/test/unit/create_manifest_data/test.ts +++ b/test/unit/create_manifest_data/test.ts @@ -1,6 +1,65 @@ import * as path from 'path'; import * as assert from 'assert'; -import create_manifest_data from '../../../src/core/create_manifest_data'; +import create_manifest_data, { template_has_preload } from '../../../src/core/create_manifest_data'; + +describe('template_has_preload', () => { + it('should detect async preload', () => { + const source = ` + + `; + assert.ok(template_has_preload(source)); + }); + + it('should detect preload in composed function', () => { + const source = ` + + `; + assert.ok(template_has_preload(source)); + }); + + it('should detect reusable preload functions', () => { + const source = ` + + `; + assert.ok(template_has_preload(source)); + }); + + it('should not detect preload functions in single line comment', () => { + const source = ` + + `; + assert.ok(!template_has_preload(source)); + }); + + it('should not detect preload functions in comment block', () => { + const source = ` + + `; + assert.ok(!template_has_preload(source)); + }); +}); describe('manifest_data', () => { it('creates routes', () => {