diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/README.md b/README.md index c66f144..2e94af8 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,15 @@ -# Typescript preprocessor for Svelte 3 +# Typescript monorepo for Svelte v3 includes -## Install - -```bash -npm i svelte-ts-preprocess -``` - -## Rollup config - -```javascript -import svelte from "rollup-plugin-svelte"; -import resolve from "rollup-plugin-node-resolve"; -import commonjs from "rollup-plugin-commonjs"; -import { terser } from "rollup-plugin-terser"; - -import { preprocess } from "svelte-ts-preprocess"; - -const production = !process.env.ROLLUP_WATCH; - -export default { - input: "src/main.js", - output: { - sourcemap: true, - format: "iife", - name: "app", - file: "public/bundle.js" - }, - plugins: [ - svelte({ - // enable run-time checks when not in production - dev: !production, - // we'll extract any component CSS out into - // a separate file — better for performance - css: css => { - css.write("public/bundle.css"); - }, - preprocess: preprocess() - }), - - // If you have external dependencies installed from - // npm, you'll most likely need these plugins. In - // some cases you'll need additional configuration — - // consult the documentation for details: - // https://github.com/rollup/rollup-plugin-commonjs - resolve(), - commonjs(), - - // If we're building for production (npm run build - // instead of npm run dev), minify - production && terser() - ] -}; -``` +- [preprocess](https://github.com/pyoner/svelte-typescript/tree/master/packages/preprocess) +- [template](https://github.com/pyoner/svelte-typescript/tree/master/packages/template) +- [types](https://github.com/pyoner/svelte-typescript/tree/master/packages/types) +- [Sapper template](https://github.com/pyoner/svelte-typescript/tree/master/packages/sapper-template) # For Contributors -To install this monorepo you can use `lerna + npm` -```bash -cd svelte-ts-preprocess -npm i lerna -g -lerna bootstrap -``` - -or `lerna + yarn` see [use workspaces](https://github.com/lerna/lerna/tree/master/commands/bootstrap#--use-workspaces) -```bash -cd svelte-ts-preprocess -yarn i lerna -g -lerna bootstrap --use-workspaces -``` +To install this monorepo you can use `pnpm` -or `yarn only` ```bash -cd svelte-ts-preprocess -yarn install +cd svelte-typescript +pnpm i -r ``` diff --git a/lerna.json b/lerna.json deleted file mode 100644 index d6707ca..0000000 --- a/lerna.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "packages": [ - "packages/*" - ], - "version": "0.0.0" -} diff --git a/package.json b/package.json index 43d8433..2ab34e2 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,36 @@ { - "private": true, - "workspaces": [ - "packages/*" + "name": "svelte-typescript-monorepo", + "private": "true", + "version": "1.0.0", + "description": "A monorepo for Svelte Typescript", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pyoner/svelte-typescript.git" + }, + "keywords": [ + "svelte", + "typescript", + "preprocess" ], - "name": "monorepo-svelte-ts-preprocess", + "author": "Jungle ", + "license": "MIT", + "bugs": { + "url": "https://github.com/pyoner/svelte-typescript/issues" + }, + "homepage": "https://github.com/pyoner/svelte-typescript#readme", "devDependencies": { - "lerna": "^3.13.3" + "husky": "^4.2.3", + "pretty-quick": "^2.0.1" + }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "dependencies": { + "typescript": "^3.9.6" } } diff --git a/packages/app/package.json b/packages/app/package.json index 028238e..290c613 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,18 +1,20 @@ { + "private": true, "name": "svelte-app", "version": "1.0.0", "devDependencies": { + "@pyoner/svelte-ts-preprocess": "workspace:^1.3.0", + "@rollup/plugin-commonjs": "^13.0.0", + "@rollup/plugin-json": "^4.0.2", + "@rollup/plugin-node-resolve": "^7.1.1", + "@wessberg/rollup-plugin-ts": "^1.2.21", "npm-run-all": "^4.1.5", - "rollup": "^1.2.2", - "rollup-plugin-commonjs": "^9.2.0", - "rollup-plugin-node-resolve": "^4.0.1", + "rollup": "^2.19.0", "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", - "rollup-plugin-typescript2": "^0.21.0", "sirv-cli": "^0.3.1", "svelte": "3.0.0", - "svelte-ts-preprocess": "*", - "typescript": "^3.4.5" + "typescript": "^3.8" }, "scripts": { "build": "rollup -c", diff --git a/packages/app/rollup.config.js b/packages/app/rollup.config.js index 3ab96f6..71ee764 100644 --- a/packages/app/rollup.config.js +++ b/packages/app/rollup.config.js @@ -1,10 +1,15 @@ import svelte from "rollup-plugin-svelte"; -import resolve from "rollup-plugin-node-resolve"; -import commonjs from "rollup-plugin-commonjs"; +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; import { terser } from "rollup-plugin-terser"; -import typescript from "rollup-plugin-typescript2"; +import typescript from "@wessberg/rollup-plugin-ts"; -import { preprocess, createEnv, readConfigFile } from "svelte-ts-preprocess"; +import { + preprocess, + createEnv, + readConfigFile +} from "@pyoner/svelte-ts-preprocess"; const production = !process.env.ROLLUP_WATCH; @@ -27,6 +32,7 @@ export default { file: "public/bundle.js" }, plugins: [ + json(), svelte({ // enable run-time checks when not in production dev: !production, diff --git a/packages/app/src/Form.svelte b/packages/app/src/Form.svelte index a88d47f..eda6c73 100644 --- a/packages/app/src/Form.svelte +++ b/packages/app/src/Form.svelte @@ -12,7 +12,7 @@ + + + +

No SSR

+ {x} +
+``` + +## Installation + +```bash +npm i -D @pyoner/svelte-nossr-preprocess +``` + +## How to use the preprocessor? + +See the [rollup config](https://github.com/pyoner/svelte-typescript/blob/master/packages/sapper-template/rollup.config.js) for Sapper diff --git a/packages/nossr/package.json b/packages/nossr/package.json new file mode 100644 index 0000000..2463f70 --- /dev/null +++ b/packages/nossr/package.json @@ -0,0 +1,31 @@ +{ + "name": "@pyoner/svelte-nossr-preprocess", + "version": "1.0.1", + "description": "No SSR preprocessor for Svelte", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc -t esnext -m commonjs -d --outDir ./dist ./src/index.ts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pyoner/svelte-typescript.git" + }, + "keywords": [ + "svelte", + "sapper", + "nossr", + "ssr", + "preprocess" + ], + "author": "Jungle ", + "license": "MIT", + "bugs": { + "url": "https://github.com/pyoner/svelte-typescript/issues" + }, + "homepage": "https://github.com/pyoner/svelte-typescript/tree/master/packages/nossr#readme", + "peerDependencies": { + "typescript": "^3.8" + } +} diff --git a/packages/nossr/src/index.ts b/packages/nossr/src/index.ts new file mode 100644 index 0000000..6cb16f7 --- /dev/null +++ b/packages/nossr/src/index.ts @@ -0,0 +1,34 @@ +interface Script { + filename: string; + content: string; + attributes: { + nossr?: string; + }; +} + +interface Markup { + content: string; + filename: string; +} + +function script({ attributes }: Script) { + const { nossr } = attributes; + if (nossr !== undefined) { + return { + code: "" + }; + } +} + +const p = /\(.|\n)*?\<\/nossr\>/gim; +function markup({ content }: Markup) { + const code = content.replace(p, ""); + return { code }; +} + +export function nossr() { + return { + script, + markup + }; +} diff --git a/packages/lib/.editorconfig b/packages/preprocess/.editorconfig similarity index 100% rename from packages/lib/.editorconfig rename to packages/preprocess/.editorconfig diff --git a/packages/preprocess/.gitignore b/packages/preprocess/.gitignore new file mode 100644 index 0000000..d626d09 --- /dev/null +++ b/packages/preprocess/.gitignore @@ -0,0 +1,12 @@ +node_modules +coverage +.nyc_output +.DS_Store +*.log +.vscode +.idea +dist +compiled +.awcache +.rpt2_cache +docs diff --git a/packages/lib/.travis.yml b/packages/preprocess/.travis.yml similarity index 100% rename from packages/lib/.travis.yml rename to packages/preprocess/.travis.yml diff --git a/packages/lib/CONTRIBUTING.md b/packages/preprocess/CONTRIBUTING.md similarity index 51% rename from packages/lib/CONTRIBUTING.md rename to packages/preprocess/CONTRIBUTING.md index 14a88e5..cdfa7ca 100644 --- a/packages/lib/CONTRIBUTING.md +++ b/packages/preprocess/CONTRIBUTING.md @@ -7,9 +7,9 @@ These steps will guide you through contributing to this project: - Fork the repo - Clone it and install dependencies - git clone https://github.com/PaulMaly/svelte-ts-preprocess + git clone https://github.com/pyoner/svelte-typescript yarn install Make and commit your changes. Make sure the commands npm run build and npm run test:prod are working. -Finally send a [GitHub Pull Request](https://github.com/PaulMaly/svelte-ts-preprocess/compare?expand=1) with a clear list of what you've done (read more [about pull requests](https://help.github.com/articles/about-pull-requests/)). Make sure all of your commits are atomic (one feature per commit). +Finally send a [GitHub Pull Request](https://github.com/pyoner/svelte-typescript/compare?expand=1) with a clear list of what you've done (read more [about pull requests](https://help.github.com/articles/about-pull-requests/)). Make sure all of your commits are atomic (one feature per commit). diff --git a/packages/lib/LICENSE b/packages/preprocess/LICENSE similarity index 94% rename from packages/lib/LICENSE rename to packages/preprocess/LICENSE index a0b43e7..4808013 100644 --- a/packages/lib/LICENSE +++ b/packages/preprocess/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 PaulMaly, Jungle +Copyright 2019 Jungle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/packages/lib/README.md b/packages/preprocess/README.md similarity index 74% rename from packages/lib/README.md rename to packages/preprocess/README.md index a3cdec1..4cd63fb 100644 --- a/packages/lib/README.md +++ b/packages/preprocess/README.md @@ -3,7 +3,7 @@ ## Install ```bash -npm i svelte-ts-preprocess +npm i @pyoner/svelte-ts-preprocess ``` ## Rollup config @@ -13,11 +13,26 @@ import svelte from "rollup-plugin-svelte"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import { terser } from "rollup-plugin-terser"; +import typescript from "rollup-plugin-typescript2"; -import { preprocess } from "svelte-ts-preprocess"; +import { + preprocess, + createEnv, + readConfigFile +} from "@pyoner/svelte-ts-preprocess"; const production = !process.env.ROLLUP_WATCH; +const env = createEnv(); +const compilerOptions = readConfigFile(env); +const opts = { + env, + compilerOptions: { + ...compilerOptions, + allowNonTsExtensions: true + } +}; + export default { input: "src/main.js", output: { @@ -35,7 +50,7 @@ export default { css: css => { css.write("public/bundle.css"); }, - preprocess: preprocess() + preprocess: preprocess(opts) }), // If you have external dependencies installed from @@ -45,6 +60,7 @@ export default { // https://github.com/rollup/rollup-plugin-commonjs resolve(), commonjs(), + typescript(), // If we're building for production (npm run build // instead of npm run dev), minify diff --git a/packages/lib/code-of-conduct.md b/packages/preprocess/code-of-conduct.md similarity index 100% rename from packages/lib/code-of-conduct.md rename to packages/preprocess/code-of-conduct.md diff --git a/packages/lib/package.json b/packages/preprocess/package.json similarity index 80% rename from packages/lib/package.json rename to packages/preprocess/package.json index 6e59b6c..1d483ce 100644 --- a/packages/lib/package.json +++ b/packages/preprocess/package.json @@ -1,27 +1,27 @@ { - "name": "svelte-ts-preprocess", - "version": "1.1.0", + "name": "@pyoner/svelte-ts-preprocess", + "version": "1.3.0", "description": "Typescript preprocessor for Svelte 3", "keywords": [ "svelte", "svelte3", - "preprocess" + "preprocess", + "typescript" ], "main": "dist/lib/svelte-ts-preprocess.js", "typings": "dist/types/svelte-ts-preprocess.d.ts", "files": [ "dist" ], - "author": "PaulMaly", - "contributors": ["Jungle "], + "author": "Jungle ", "repository": { "type": "git", - "url": "https://github.com/PaulMaly/svelte-ts-preprocess" + "url": "https://github.com/pyoner/svelte-typescript" }, "bugs": { - "url": "https://github.com/PaulMaly/svelte-ts-preprocess/issues" + "url": "https://github.com/pyoner/svelte-typescript/issues" }, - "homepage": "https://github.com/PaulMaly/svelte-ts-preprocess", + "homepage": "https://github.com/pyoner/svelte-typescript", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -29,7 +29,7 @@ "scripts": { "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", "prebuild": "rimraf dist", - "build": "tsc && typedoc --out docs --target es6 --theme minimal --mode file src", + "build": "tsc -p ./tsconfig.json", "start": "tsc -w", "test": "jest --coverage", "test:watch": "jest --coverage --watch", @@ -93,16 +93,14 @@ "devDependencies": { "@commitlint/cli": "^7.1.2", "@commitlint/config-conventional": "^7.1.2", - "@types/jest": "^24.0.11", "@types/node": "^11.13.6", "colors": "^1.3.2", "commitizen": "^3.0.0", "coveralls": "^3.0.2", "cross-env": "^5.2.0", "cz-conventional-changelog": "^2.1.0", - "husky": "^1.3.1", - "jest": "^24.7.1", - "jest-config": "^24.7.1", + "jest": "^24.9.0", + "jest-config": "^24.9.0", "lint-staged": "^8.0.0", "lodash.camelcase": "^4.3.0", "prettier": "^1.14.3", @@ -112,14 +110,14 @@ "semantic-release": "^15.9.16", "shelljs": "^0.8.3", "travis-deploy-once": "^5.0.9", - "ts-jest": "^24.0.2", + "ts-jest": "^24.1.0", "ts-node": "^8.1.0", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", "tslint-config-standard": "^8.0.1", "typedoc": "^0.14.2" }, - "dependencies": { - "typescript": "^3.4.4" + "peerDependencies": { + "typescript": "^3.8" } } diff --git a/packages/lib/src/svelte-ts-preprocess.ts b/packages/preprocess/src/svelte-ts-preprocess.ts similarity index 72% rename from packages/lib/src/svelte-ts-preprocess.ts rename to packages/preprocess/src/svelte-ts-preprocess.ts index 8046477..a344f03 100644 --- a/packages/lib/src/svelte-ts-preprocess.ts +++ b/packages/preprocess/src/svelte-ts-preprocess.ts @@ -1,3 +1,5 @@ +import fs from 'fs' +import path from 'path' import ts from 'typescript' const LANGS = ['ts', 'typescript'] @@ -6,17 +8,16 @@ function importTransformer(): ts.TransformerFactory { return context => { const visit: ts.Visitor = node => { if (ts.isImportDeclaration(node)) { - const text = node.moduleSpecifier.getText().slice(0, -1) - if (text.endsWith('.svelte')) { - // console.log('------- svelte import -----') - // console.log(node.getFullText().trim()) - return ts.createImportDeclaration( - node.decorators, - node.modifiers, - node.importClause, - node.moduleSpecifier - ) + if (node.importClause?.isTypeOnly) { + return node } + + return ts.createImportDeclaration( + node.decorators, + node.modifiers, + node.importClause, + node.moduleSpecifier + ) } return ts.visitEachChild(node, child => visit(child), context) } @@ -50,27 +51,39 @@ interface File { function createProxyHost(host: ts.CompilerHost, file: File) { const proxy: ts.CompilerHost = { - getSourceFile: ( - fileName: string, + getSourceFile( + filename: string, languageVersion: ts.ScriptTarget, _onError?: (message: string) => void - ) => { - return fileName === file.name + ) { + filename = ts.sys.resolvePath(filename) + return filename === file.name ? ts.createSourceFile(file.name, file.content, languageVersion) - : host.getSourceFile(fileName, languageVersion, _onError) + : host.getSourceFile(filename, languageVersion, _onError) }, - writeFile: (_fileName, _content) => { + + writeFile: (_filename, _content) => { throw new Error('unsupported') }, - getCanonicalFileName: fileName => - fileName === file.name + + getCanonicalFileName(filename) { + filename = ts.sys.resolvePath(filename) + return filename === file.name ? ts.sys.useCaseSensitiveFileNames - ? fileName - : fileName.toLowerCase() - : host.getCanonicalFileName(fileName), + ? filename + : filename.toLowerCase() + : host.getCanonicalFileName(filename) + }, + + fileExists(filename) { + filename = ts.sys.resolvePath(filename) + return filename === file.name ? true : host.fileExists(filename) + }, - fileExists: fileName => (fileName === file.name ? true : host.fileExists(fileName)), - readFile: fileName => (fileName === file.name ? file.content : host.readFile(fileName)), + readFile(filename) { + filename = ts.sys.resolvePath(filename) + return filename === file.name ? file.content : host.readFile(filename) + }, getDefaultLibFileName: host.getDefaultLibFileName.bind(host), getCurrentDirectory: host.getCurrentDirectory.bind(host), @@ -87,6 +100,7 @@ interface Script { content: string attributes: { lang?: string + src?: string } } @@ -135,6 +149,7 @@ export function readConfigFile(env: Env, path?: string) { export interface PreprocessOptions { compilerOptions: ts.CompilerOptions env: Env + hideErrors: boolean } export function createPreprocessOptions(opts?: Partial): PreprocessOptions { @@ -142,7 +157,8 @@ export function createPreprocessOptions(opts?: Partial): Prep return { compilerOptions: opts.compilerOptions ? opts.compilerOptions : defaultCompilerOptions, - env: opts.env ? opts.env : createEnv() + env: opts.env ? opts.env : createEnv(), + hideErrors: !!opts.hideErrors } } @@ -157,6 +173,13 @@ export function preprocess(opts?: Partial) { return } + if (attributes.src) { + const dir = path.parse(filename).dir + filename = path.join(dir, attributes.src) + content = fs.readFileSync(filename).toString() + } + + filename = ts.sys.resolvePath(filename) const options = createPreprocessOptions(opts) const rootFiles = [filename] @@ -181,13 +204,15 @@ export function preprocess(opts?: Partial) { const program = ts.createProgram(rootFiles, options.compilerOptions, proxyHost) program.emit(undefined, writeFile, undefined, undefined, customTransformers) - const diagnostics = clearDiagnostics(ts.getPreEmitDiagnostics(program)) - if (diagnostics.length) { - const s = ts.formatDiagnosticsWithColorAndContext( - diagnostics, - options.env.formatDiagnosticHost - ) - console.log(s) + if (!options.hideErrors) { + const diagnostics = clearDiagnostics(ts.getPreEmitDiagnostics(program)) + if (diagnostics.length) { + const s = ts.formatDiagnosticsWithColorAndContext( + diagnostics, + options.env.formatDiagnosticHost + ) + console.log(s) + } } return { code } diff --git a/packages/preprocess/test/svelte-ts-preprocess.test.ts b/packages/preprocess/test/svelte-ts-preprocess.test.ts new file mode 100644 index 0000000..155f16d --- /dev/null +++ b/packages/preprocess/test/svelte-ts-preprocess.test.ts @@ -0,0 +1,102 @@ +import { preprocess } from '../src/svelte-ts-preprocess' + +describe('preprocess test', () => { + const opts = { hideErrors: true } + + it('should be function', () => { + expect(preprocess).toBeInstanceOf(Function) + }) + + it('returns object with "script" property', () => { + expect(preprocess(opts)).toHaveProperty('script') + }) + + it('run preprocess', () => { + // const code = `` + const content = `//comment +import Form from './Form.svelte'; + +function x(){return 5;} +console.log(x()) +let c: number = 5; +` + const filename = 'Component.svelte' + const attributes = { + lang: 'ts' + } + const result = preprocess(opts).script({ + content, + filename, + attributes + }) + expect(result).toHaveProperty('code') + }) + + it('should preserve all imports', () => { + const content = `import Form from './Form.svelte'; +import x from 'x-lib'; +` + const filename = 'Component.svelte' + const attributes = { + lang: 'ts' + } + const result = preprocess(opts).script({ + content, + filename, + attributes + }) + expect(result).toHaveProperty('code', content) + }) + + it('should remove types imports', () => { + const content = `import Form from './Form.svelte'; +import type x from 'x-lib'; +let a: x = 5; +` + const expected = `import Form from './Form.svelte'; +let a = 5; +` + const filename = 'Component.svelte' + const attributes = { + lang: 'ts' + } + const result = preprocess(opts).script({ + content, + filename, + attributes + }) + expect(result).toHaveProperty('code', expected) + }) + + it('should hide errors', () => { + const content = `import Form from './Form.svelte'; +import x from 'x-lib'; +` + const filename = 'Component.svelte' + const attributes = { + lang: 'ts' + } + const opts = { hideErrors: true } + const result = preprocess(opts).script({ + content, + filename, + attributes + }) + expect(result).toHaveProperty('code', content) + }) + + it('should support external .ts files', () => { + const content = '' + const filename = 'Component.svelte' + const attributes = { + lang: 'ts', + src: 'src/svelte-ts-preprocess.ts' + } + const result = preprocess(opts).script({ + content, + filename, + attributes + }) + expect(result).toHaveProperty('code') + }) +}) diff --git a/packages/lib/tools/gh-pages-publish.ts b/packages/preprocess/tools/gh-pages-publish.ts similarity index 100% rename from packages/lib/tools/gh-pages-publish.ts rename to packages/preprocess/tools/gh-pages-publish.ts diff --git a/packages/lib/tools/semantic-release-prepare.ts b/packages/preprocess/tools/semantic-release-prepare.ts similarity index 100% rename from packages/lib/tools/semantic-release-prepare.ts rename to packages/preprocess/tools/semantic-release-prepare.ts diff --git a/packages/lib/tsconfig.json b/packages/preprocess/tsconfig.json similarity index 100% rename from packages/lib/tsconfig.json rename to packages/preprocess/tsconfig.json diff --git a/packages/lib/tslint.json b/packages/preprocess/tslint.json similarity index 100% rename from packages/lib/tslint.json rename to packages/preprocess/tslint.json diff --git a/packages/sapper-template/.gitignore b/packages/sapper-template/.gitignore new file mode 100644 index 0000000..f5e593c --- /dev/null +++ b/packages/sapper-template/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +/node_modules/ +/src/node_modules/@sapper/ +yarn-error.log +/cypress/screenshots/ +/__sapper__/ +.rpt2_cache diff --git a/packages/sapper-template/README.md b/packages/sapper-template/README.md new file mode 100644 index 0000000..0de21f3 --- /dev/null +++ b/packages/sapper-template/README.md @@ -0,0 +1,103 @@ +# sapper-template + +## Install + +### For Linux users +```bash +mkdir sapper-app +curl -L https://github.com/pyoner/svelte-typescript/tarball/master > svelte-typescript.tar +tar --strip-components=3 --wildcards --one-top-level=sapper-app -xf svelte-typescript.tar */packages/sapper-template +``` + +### For Mac users +```zsh +mkdir sapper-app +curl -L https://github.com/pyoner/svelte-typescript/tarball/master > svelte-typescript.tar +tar --strip-components=3 -C sapper-app -xf svelte-typescript.tar '*/packages/sapper-template/' +``` + +### For Windows users +Download https://github.com/pyoner/svelte-typescript/archive/master.zip and extract template from `packages/sapper-template` + +## Usage + +```bash +cd sapper-app +npm install # or yarn! +npm run dev +``` + +Open up [localhost:3000](http://localhost:3000) and start clicking around. + +Consult [sapper.svelte.dev](https://sapper.svelte.dev) for help getting started. + + +## Structure + +Sapper expects to find two directories in the root of your project — `src` and `static`. + + +### src + +The [src](src) directory contains the entry points for your app — `client.js`, `server.js` and (optionally) a `service-worker.js` — along with a `template.html` file and a `routes` directory. + + +#### src/routes + +This is the heart of your Sapper app. There are two kinds of routes — *pages*, and *server routes*. + +**Pages** are Svelte components written in `.svelte` files. When a user first visits the application, they will be served a server-rendered version of the route in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel. (Sapper will preload and cache the code for these subsequent pages, so that navigation is instantaneous.) + +**Server routes** are modules written in `.js` files, that export functions corresponding to HTTP methods. Each function receives Express `request` and `response` objects as arguments, plus a `next` function. This is useful for creating a JSON API, for example. + +There are three simple rules for naming the files that define your routes: + +* A file called `src/routes/about.svelte` corresponds to the `/about` route. A file called `src/routes/blog/[slug].svelte` corresponds to the `/blog/:slug` route, in which case `params.slug` is available to the route +* The file `src/routes/index.svelte` (or `src/routes/index.js`) corresponds to the root of your app. `src/routes/about/index.svelte` is treated the same as `src/routes/about.svelte`. +* Files and directories with a leading underscore do *not* create routes. This allows you to colocate helper modules and components with the routes that depend on them — for example you could have a file called `src/routes/_helpers/datetime.js` and it would *not* create a `/_helpers/datetime` route + + +### static + +The [static](static) directory contains any static assets that should be available. These are served using [sirv](https://github.com/lukeed/sirv). + +In your [service-worker.js](app/service-worker.js) file, you can import these as `files` from the generated manifest... + +```js +import { files } from '@sapper/service-worker'; +``` + +...so that you can cache them (though you can choose not to, for example if you don't want to cache very large files). + + +## Bundler config + +Sapper uses Rollup or webpack to provide code-splitting and dynamic imports, as well as compiling your Svelte components. With webpack, it also provides hot module reloading. As long as you don't do anything daft, you can edit the configuration files to add whatever plugins you'd like. + + +## Production mode and deployment + +To start a production version of your app, run `npm run build && npm start`. This will disable live reloading, and activate the appropriate bundler plugins. + +You can deploy your application to any environment that supports Node 8 or above. As an example, to deploy to [Now](https://zeit.co/now), run these commands: + +```bash +npm install -g now +now +``` + + +## Using external components with webpack + +When using Svelte components installed from npm, such as [@sveltejs/svelte-virtual-list](https://github.com/sveltejs/svelte-virtual-list), Svelte needs the original component source (rather than any precompiled JavaScript that ships with the component). This allows the component to be rendered server-side, and also keeps your client-side app smaller. + +Because of that, it's essential that webpack doesn't treat the package as an *external dependency*. You can either modify the `externals` option under `server` in [webpack.config.js](webpack.config.js), or simply install the package to `devDependencies` rather than `dependencies`, which will cause it to get bundled (and therefore compiled) with your app: + +```bash +npm install -D @sveltejs/svelte-virtual-list +``` + + +## Bugs and feedback + +Sapper is in early development, and may have the odd rough edge here and there. Please be vocal over on the [Sapper issue tracker](https://github.com/sveltejs/sapper/issues). diff --git a/packages/sapper-template/appveyor.yml b/packages/sapper-template/appveyor.yml new file mode 100644 index 0000000..e75da3b --- /dev/null +++ b/packages/sapper-template/appveyor.yml @@ -0,0 +1,18 @@ +version: "{build}" + +shallow_clone: true + +init: + - git config --global core.autocrlf false + +build: off + +environment: + matrix: + # node.js + - nodejs_version: stable + +install: + - ps: Install-Product node $env:nodejs_version + - npm install cypress + - npm install diff --git a/packages/sapper-template/cypress.json b/packages/sapper-template/cypress.json new file mode 100644 index 0000000..f5622fa --- /dev/null +++ b/packages/sapper-template/cypress.json @@ -0,0 +1,4 @@ +{ + "baseUrl": "http://localhost:3000", + "video": false +} \ No newline at end of file diff --git a/packages/sapper-template/cypress/fixtures/example.json b/packages/sapper-template/cypress/fixtures/example.json new file mode 100644 index 0000000..da18d93 --- /dev/null +++ b/packages/sapper-template/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/packages/sapper-template/cypress/integration/spec.js b/packages/sapper-template/cypress/integration/spec.js new file mode 100644 index 0000000..9a7140d --- /dev/null +++ b/packages/sapper-template/cypress/integration/spec.js @@ -0,0 +1,19 @@ +describe('Sapper template app', () => { + beforeEach(() => { + cy.visit('/') + }); + + it('has the correct

', () => { + cy.contains('h1', 'Great success!') + }); + + it('navigates to /about', () => { + cy.get('nav a').contains('about').click(); + cy.url().should('include', '/about'); + }); + + it('navigates to /blog', () => { + cy.get('nav a').contains('blog').click(); + cy.url().should('include', '/blog'); + }); +}); \ No newline at end of file diff --git a/packages/sapper-template/cypress/plugins/index.js b/packages/sapper-template/cypress/plugins/index.js new file mode 100644 index 0000000..fd170fb --- /dev/null +++ b/packages/sapper-template/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/packages/sapper-template/cypress/support/commands.js b/packages/sapper-template/cypress/support/commands.js new file mode 100644 index 0000000..c1f5a77 --- /dev/null +++ b/packages/sapper-template/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/packages/sapper-template/cypress/support/index.js b/packages/sapper-template/cypress/support/index.js new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/packages/sapper-template/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/packages/sapper-template/package.json b/packages/sapper-template/package.json new file mode 100644 index 0000000..734448f --- /dev/null +++ b/packages/sapper-template/package.json @@ -0,0 +1,43 @@ +{ + "private": true, + "name": "sapper-template", + "description": "Sapper", + "version": "0.0.1", + "scripts": { + "dev": "sapper dev", + "build": "sapper build --legacy", + "export": "sapper export --legacy", + "start": "node __sapper__/build", + "cy:run": "cypress run", + "cy:open": "cypress open", + "test": "run-p --race dev cy:run" + }, + "dependencies": { + "compression": "^1.7.1", + "polka": "^0.5.0", + "sirv": "^0.4.0" + }, + "devDependencies": { + "@babel/core": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/preset-env": "^7.0.0", + "@babel/runtime": "^7.0.0", + "@pyoner/svelte-nossr-preprocess": "^1.0.1", + "@pyoner/svelte-ts-preprocess": "^1.3.0", + "@rollup/plugin-commonjs": "^13.0.0", + "@rollup/plugin-json": "^4.0.2", + "@rollup/plugin-node-resolve": "^7.1.1", + "@types/node": "^12.0.8", + "@wessberg/rollup-plugin-ts": "^1.2.13", + "npm-run-all": "^4.1.5", + "rollup": "^2.19.0", + "rollup-plugin-babel": "^4.0.2", + "rollup-plugin-replace": "^2.0.0", + "rollup-plugin-svelte": "^5.0.1", + "rollup-plugin-terser": "^4.0.4", + "sapper": "^0.27.0", + "svelte": "^3.12.1", + "typescript": "^3.4.5" + } +} diff --git a/packages/sapper-template/rollup.config.js b/packages/sapper-template/rollup.config.js new file mode 100644 index 0000000..667c493 --- /dev/null +++ b/packages/sapper-template/rollup.config.js @@ -0,0 +1,122 @@ +import resolve from "@rollup/plugin-node-resolve"; +import replace from "rollup-plugin-replace"; +import commonjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; +import svelte from "rollup-plugin-svelte"; +import babel from "rollup-plugin-babel"; +import { terser } from "rollup-plugin-terser"; +import typescript from "@wessberg/rollup-plugin-ts"; +import config from "sapper/config/rollup.js"; +import pkg from "./package.json"; +import { nossr } from "@pyoner/svelte-nossr-preprocess"; + +const svelteOptions = require("./svelte.config"); +const sveltePreprocessors = [nossr(), svelteOptions.preprocess]; + +const production = !process.env.ROLLUP_WATCH; + +const mode = process.env.NODE_ENV; +const dev = mode === "development"; +const legacy = !!process.env.SAPPER_LEGACY_BUILD; + +const onwarn = (warning, onwarn) => + (warning.code === "CIRCULAR_DEPENDENCY" && + /[/\\]@sapper[/\\]/.test(warning.message)) || + onwarn(warning); + +export default { + client: { + input: config.client.input(), + output: config.client.output(), + plugins: [ + replace({ + "process.browser": true, + "process.env.NODE_ENV": JSON.stringify(mode) + }), + json(), + svelte({ + ...svelteOptions, + dev, + hydratable: true, + emitCss: true + }), + resolve({ + browser: true + }), + commonjs(), + typescript(), + + legacy && + babel({ + extensions: [".js", ".mjs", ".html", ".svelte"], + runtimeHelpers: true, + exclude: ["node_modules/@babel/**"], + presets: [ + [ + "@babel/preset-env", + { + targets: "> 0.25%, not dead" + } + ] + ], + plugins: [ + "@babel/plugin-syntax-dynamic-import", + [ + "@babel/plugin-transform-runtime", + { + useESModules: true + } + ] + ] + }), + + !dev && + terser({ + module: true + }) + ], + + onwarn + }, + + server: { + input: config.server.input(), + output: config.server.output(), + plugins: [ + replace({ + "process.browser": false, + "process.env.NODE_ENV": JSON.stringify(mode) + }), + svelte({ + preprocess: sveltePreprocessors, + generate: "ssr", + dev + }), + resolve(), + commonjs(), + typescript() + ], + external: Object.keys(pkg.dependencies).concat( + require("module").builtinModules || + Object.keys(process.binding("natives")) + ), + + onwarn + }, + + serviceworker: { + input: config.serviceworker.input(), + output: config.serviceworker.output(), + plugins: [ + resolve(), + replace({ + "process.browser": true, + "process.env.NODE_ENV": JSON.stringify(mode) + }), + commonjs(), + !dev && terser() + ], + + onwarn + } +}; diff --git a/packages/sapper-template/src/client.js b/packages/sapper-template/src/client.js new file mode 100644 index 0000000..cec9172 --- /dev/null +++ b/packages/sapper-template/src/client.js @@ -0,0 +1,5 @@ +import * as sapper from '@sapper/app'; + +sapper.start({ + target: document.querySelector('#sapper') +}); \ No newline at end of file diff --git a/packages/sapper-template/src/components/Counter.svelte b/packages/sapper-template/src/components/Counter.svelte new file mode 100644 index 0000000..d23a7fc --- /dev/null +++ b/packages/sapper-template/src/components/Counter.svelte @@ -0,0 +1,13 @@ +
+ Default Counter +
+ {value} + + +
+
+ + diff --git a/packages/sapper-template/src/components/Nav.svelte b/packages/sapper-template/src/components/Nav.svelte new file mode 100644 index 0000000..ad3c894 --- /dev/null +++ b/packages/sapper-template/src/components/Nav.svelte @@ -0,0 +1,74 @@ + + + + + diff --git a/packages/sapper-template/src/routes/_error.svelte b/packages/sapper-template/src/routes/_error.svelte new file mode 100644 index 0000000..320e587 --- /dev/null +++ b/packages/sapper-template/src/routes/_error.svelte @@ -0,0 +1,40 @@ + + + + + + {status} + + +

{status}

+ +

{error.message}

+ +{#if dev && error.stack} +
{error.stack}
+{/if} diff --git a/packages/sapper-template/src/routes/_layout.svelte b/packages/sapper-template/src/routes/_layout.svelte new file mode 100644 index 0000000..8432299 --- /dev/null +++ b/packages/sapper-template/src/routes/_layout.svelte @@ -0,0 +1,22 @@ + + + + +