├── .eslintrc.js ├── .github └── workflows │ ├── main.yml │ └── xbrowser.yml ├── .gitignore ├── .prettierrc ├── README.md ├── e2e ├── _helpers.ts ├── _runServer.ts └── runWithSelenium.test.ts ├── jest.config.js ├── karma.conf.js ├── package.json ├── src ├── __tests__ │ ├── example.karma.ts │ ├── example.test.ts │ └── flaky-retry.test.ts ├── add.ts ├── index.html └── index.ts ├── tsconfig.json ├── webpack.config.js └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["eslint:recommended", "plugin:prettier/recommended"], 3 | env: { 4 | es6: true, 5 | browser: true, 6 | node: true, 7 | jest: true 8 | }, 9 | plugins: ["@typescript-eslint"], 10 | parser: "@typescript-eslint/parser", 11 | parserOptions: { 12 | sourceType: "module" 13 | }, 14 | rules: { 15 | "no-unused-vars": "off", 16 | "@typescript-eslint/no-unused-vars": [ 17 | "error", 18 | { argsIgnorePattern: "^_", varsIgnorePattern: "^_" } 19 | ] 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: [push] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: actions/setup-node@v1 11 | with: 12 | node-version: 12 13 | - run: yarn install 14 | - run: yarn lint 15 | - run: yarn typecheck 16 | - run: yarn test:unittest 17 | # test-with-puppeteer: 18 | # runs-on: ubuntu-latest 19 | # steps: 20 | # - uses: actions/checkout@v1 21 | # - uses: actions/setup-node@v1 22 | # with: 23 | # node-version: 12 24 | # - run: | 25 | # yarn install 26 | # yarn build 27 | # - run: yarn test:e2e-puppeteer 28 | -------------------------------------------------------------------------------- /.github/workflows/xbrowser.yml: -------------------------------------------------------------------------------- 1 | name: xbrowser 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: windows-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: actions/setup-node@v1 11 | with: 12 | node-version: 12 13 | - name: cache node_modules 14 | uses: actions/cache@v1 15 | with: 16 | path: node_modules 17 | key: xbrowser-yarn-${{ hashFiles('**\yarn.lock') }} 18 | restore-keys: | 19 | xbrowser-yarn- 20 | - name: cache dist 21 | uses: actions/cache@v1 22 | with: 23 | path: dist 24 | key: dist-${GITHUB_SHA} 25 | restore-keys: | 26 | dist-${GITHUB_SHA} 27 | - run: yarn install 28 | - run: yarn build 29 | e2e-win-matrix: 30 | needs: [build] 31 | runs-on: windows-latest 32 | strategy: 33 | matrix: 34 | browser: [ie, firefox, chrome] 35 | steps: 36 | - uses: actions/checkout@v1 37 | - uses: actions/setup-node@v1 38 | with: 39 | node-version: 12 40 | - name: Use node_modules cache 41 | uses: actions/cache@v1 42 | with: 43 | path: node_modules 44 | key: xbrowser-yarn-${{ hashFiles('**\yarn.lock') }} 45 | restore-keys: | 46 | xbrowser-yarn- 47 | - name: Use dist cache 48 | uses: actions/cache@v1 49 | with: 50 | path: dist 51 | key: dist-${GITHUB_SHA} 52 | restore-keys: | 53 | dist-${GITHUB_SHA} 54 | # For IE Webdriver 55 | - name: Cache IEDriver 56 | uses: actions/cache@v1 57 | id: iedriver-cache 58 | with: 59 | path: Selenium.WebDriver.IEDriver.3.150.0 60 | key: IEDriver.3.150.0 61 | - if: matrix.browser == 'ie' 62 | uses: warrenbuckley/Setup-Nuget@v1 63 | - if: matrix.browser == 'ie' && steps.iedriver-cache.outputs.cache-hit != 'true' 64 | run: nuget install Selenium.WebDriver.IEDriver -Version 3.150.0 65 | # Run 66 | - run: yarn test:karma:${{ matrix.browser }} 67 | - run: yarn test:e2e:${{ matrix.browser }} 68 | 69 | # does not work: You must enable the 'Allow Remote Automation' option in Safari's Develop menu to control Safari via WebDriver 70 | # e2e-safari: 71 | # runs-on: macos-latest 72 | # needs: [build] 73 | # steps: 74 | # - uses: actions/checkout@v1 75 | # - uses: actions/setup-node@v1 76 | # with: 77 | # node-version: 12 78 | # - uses: actions/cache@v1 79 | # with: 80 | # path: ~/.cache/yarn 81 | # key: xbrowser-mac-yarn-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 82 | # restore-keys: | 83 | # xbrowser-mac-yarn- 84 | # - uses: actions/cache@v1 85 | # with: 86 | # path: dist 87 | # key: dist-${GITHUB_SHA} 88 | # restore-keys: | 89 | # dist-${GITHUB_SHA} 90 | # - run: yarn install 91 | # - run: | 92 | # defaults write com.apple.Safari IncludeDevelopMenu YES 93 | # defaults write com.apple.Safari AllowRemoteAutomation 1 94 | # sudo safaridriver --enable 95 | # safaridriver -p 0 & 96 | # # - run: yarn test:karma:safari 97 | # - run: yarn test:e2e:safari 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/50e42aa1064d004a5c99eaa72a2d8054a0d8de55/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Optional REPL history 59 | .node_repl_history 60 | 61 | # Output of 'npm pack' 62 | *.tgz 63 | 64 | # Yarn Integrity file 65 | .yarn-integrity 66 | 67 | # dotenv environment variables file 68 | .env 69 | .env.test 70 | 71 | # parcel-bundler cache (https://parceljs.org/) 72 | .cache 73 | 74 | # next.js build output 75 | .next 76 | 77 | # nuxt.js build output 78 | .nuxt 79 | 80 | # vuepress build output 81 | .vuepress/dist 82 | 83 | # Serverless directories 84 | .serverless/ 85 | 86 | # FuseBox cache 87 | .fusebox/ 88 | 89 | # DynamoDB Local files 90 | .dynamodb/ 91 | 92 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Frontend GH Action Playground 2 | 3 | - build 4 | - typescript typecheck 5 | - eslint (@typescript-eslint) 6 | - jest unittest 7 | - puppeteer e2e test 8 | 9 | ## LICENSE 10 | 11 | MIT 12 | -------------------------------------------------------------------------------- /e2e/_helpers.ts: -------------------------------------------------------------------------------- 1 | import { Server } from "http"; 2 | import path from "path"; 3 | import express from "express"; 4 | import webdriver from "selenium-webdriver"; 5 | 6 | export async function startServer(port: number = 0): Promise { 7 | const app = express(); 8 | app.use(express.static(path.join(__dirname, "../dist"))); 9 | let server: Server = null as any; 10 | await new Promise(r => (server = app.listen(port, r))); 11 | return server as Server; 12 | } 13 | 14 | // puppeteer like wrapper 15 | export class Page { 16 | constructor(private _driver: webdriver.WebDriver) {} 17 | 18 | async ensureNoError() { 19 | const logs = await this._driver 20 | .manage() 21 | .logs() 22 | .get("browser"); 23 | const errorLogs = logs.filter((log: any) => log.level.name_ === "SEVERE"); 24 | if (errorLogs.length > 0) { 25 | throw new Error(JSON.stringify(errorLogs)); 26 | } 27 | } 28 | 29 | async getText(selector: string) { 30 | const elem = this._driver.findElement(webdriver.By.css(selector)); 31 | return await elem.getText(); 32 | } 33 | 34 | async loadUrl(url: string) { 35 | await this._driver.get(url); 36 | } 37 | 38 | async waitFor(selector: string, timeout = 150000) { 39 | await this._driver.wait( 40 | webdriver.until.elementLocated(webdriver.By.css(selector)), 41 | timeout 42 | ); 43 | } 44 | 45 | async evaluate(code: string) { 46 | return this._driver.executeScript(code); 47 | } 48 | 49 | async title() { 50 | return this._driver.getTitle(); 51 | } 52 | 53 | async close() { 54 | return this._driver.quit(); 55 | } 56 | 57 | click(selector: string) { 58 | this._driver.findElement(webdriver.By.css(selector)).click(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /e2e/_runServer.ts: -------------------------------------------------------------------------------- 1 | import { startServer } from "./_helpers"; 2 | 3 | startServer(); 4 | -------------------------------------------------------------------------------- /e2e/runWithSelenium.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import webdriver from "selenium-webdriver"; 3 | import assert from "assert"; 4 | import path from "path"; 5 | import { Server } from "http"; 6 | import { AddressInfo } from "net"; 7 | import { startServer, Page } from "./_helpers"; 8 | 9 | jest.retryTimes(3); 10 | jest.setTimeout(30 * 1000); 11 | 12 | let server: Server; 13 | let port: number; 14 | let page: Page; 15 | 16 | beforeAll(async () => { 17 | server = await startServer(4000); 18 | port = (server.address() as AddressInfo).port; 19 | let capabilities: webdriver.Capabilities = null as any; 20 | switch (process.env.BROWSER || "chrome") { 21 | case "ie": { 22 | // HACK: include IEDriver path by nuget 23 | const driverPath = path.join( 24 | __dirname, 25 | "../Selenium.WebDriver.IEDriver.3.150.0/driver/" 26 | ); 27 | process.env.PATH = `${process.env.PATH};${driverPath};`; 28 | capabilities = webdriver.Capabilities.ie(); 29 | capabilities.set("ignoreProtectedModeSettings", true); 30 | capabilities.set("ignoreZoomSetting", true); 31 | break; 32 | } 33 | case "safari": { 34 | capabilities = webdriver.Capabilities.safari(); 35 | break; 36 | } 37 | case "firefox": { 38 | require("geckodriver"); 39 | capabilities = webdriver.Capabilities.firefox(); 40 | break; 41 | } 42 | case "chrome": { 43 | require("chromedriver"); 44 | capabilities = webdriver.Capabilities.chrome(); 45 | capabilities.set("chromeOptions", { 46 | args: [ 47 | "--headless", 48 | "--no-sandbox", 49 | "--disable-gpu", 50 | "--window-size=1980,1200" 51 | ] 52 | }); 53 | break; 54 | } 55 | } 56 | const driver = await new webdriver.Builder() 57 | .withCapabilities(capabilities) 58 | .build(); 59 | page = new Page(driver); 60 | }); 61 | 62 | afterAll(async () => { 63 | page && (await page.close()); 64 | server.close(); 65 | }); 66 | 67 | it("Google", async () => { 68 | await page.loadUrl(`http://google.com`); 69 | assert.equal(await page.title(), "Google"); 70 | }); 71 | 72 | it("Title is 'test'", async () => { 73 | await page.loadUrl(`http://localhost:${port}/`); 74 | assert.equal(await page.title(), "test"); 75 | }); 76 | 77 | it("Root content is 'hello'", async () => { 78 | await page.loadUrl(`http://localhost:${port}/`); 79 | const value = await page.getText("[data-testid='root']"); 80 | assert.equal(value, "hello"); 81 | }); 82 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: [""], 3 | transform: { 4 | "^.+\\.tsx?$": "ts-jest" 5 | }, 6 | testRunner: "jest-circus/runner", 7 | testRegex: "(/(__tests__|e2e)/.*|(\\.|/))\\.test\\.tsx?$", 8 | coveragePathIgnorePatterns: ["dist", "node_modules"], 9 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"] 10 | }; 11 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | module.exports = function(config) { 3 | config.set({ 4 | basePath: "", 5 | frameworks: ["jasmine"], 6 | exclude: [], 7 | reporters: ["progress"], 8 | port: 9876, 9 | colors: true, 10 | logLevel: config.LOG_INFO, 11 | autoWatch: true, 12 | browsers: ["ChromeHeadless"], 13 | singleRun: false, 14 | concurrency: Infinity, 15 | files: ["src/**/*.karma.ts"], 16 | preprocessors: { 17 | "src/**/*.karma.ts": ["webpack"] 18 | }, 19 | webpack: { 20 | mode: "development", 21 | resolve: { 22 | extensions: [".js", ".json", ".ts"] 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.js$/, 28 | use: "babel-loader" 29 | }, 30 | { test: /\.ts$/, use: "ts-loader" } 31 | ] 32 | }, 33 | plugins: [ 34 | new webpack.DefinePlugin({ 35 | "process.env.test": true 36 | }) 37 | ] 38 | }, 39 | customLaunchers: { 40 | ie_no_addons: { 41 | base: "IE", 42 | flags: ["-extoff"] 43 | } 44 | } 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "action-playground", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "mizchi ", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "webpack-dev-server --mode development", 9 | "build": "webpack --mode production", 10 | "typecheck": "tsc -p . --noEmit", 11 | "lint": "eslint src e2e --ext='.ts,.tsx,.js'", 12 | "format": "prettier --write '{src,e2e}/**/*.{ts,tsx,js}'", 13 | "test": "run-s test:*", 14 | "test:unittest": "jest src --coverage --max-cpu=4", 15 | "test:e2e:ie": "cross-env BROWSER=ie jest e2e/runWithSelenium.test.ts", 16 | "test:e2e:chrome": "cross-env BROWSER=chrome jest e2e/runWithSelenium.test.ts", 17 | "test:e2e:firefox": "cross-env BROWSER=firefox jest e2e/runWithSelenium.test.ts", 18 | "test:e2e:safari": "cross-env BROWSER=safari jest e2e/runWithSelenium.test.ts", 19 | "test:karma:ie": "karma start --single-run --browsers ie_no_addons", 20 | "test:karma:chrome": "karma start --single-run --browsers Chrome", 21 | "test:karma:firefox": "karma start --single-run --browsers Firefox", 22 | "test:karma:safari": "karma start --single-run --browsers Safari" 23 | }, 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "@types/express": "^4.17.2", 27 | "@types/http-server": "^0.10.0", 28 | "@types/jest": "^24.0.22", 29 | "@types/node": "^12.12.6", 30 | "@types/puppeteer": "^1.20.2", 31 | "@types/selenium-webdriver": "^4.0.5", 32 | "@types/webpack": "^4.39.8", 33 | "@typescript-eslint/eslint-plugin": "^2.6.1", 34 | "@typescript-eslint/parser": "^2.6.1", 35 | "babel-loader": "^8.0.6", 36 | "chromedriver": "76", 37 | "cross-env": "^6.0.3", 38 | "eslint": "^6.6.0", 39 | "eslint-config-prettier": "^6.5.0", 40 | "eslint-plugin-prettier": "^3.1.1", 41 | "express": "^4.17.1", 42 | "geckodriver": "^1.19.1", 43 | "html-webpack-plugin": "^3.2.0", 44 | "jasmine": "^3.5.0", 45 | "jasmine-core": "^3.5.0", 46 | "jest": "^24.9.0", 47 | "jest-circus": "^24.9.0", 48 | "karma": "^4.4.1", 49 | "karma-chrome-launcher": "^3.1.0", 50 | "karma-firefox-launcher": "^1.2.0", 51 | "karma-ie-launcher": "^1.0.0", 52 | "karma-jasmine": "^2.0.1", 53 | "karma-safari-launcher": "^1.0.0", 54 | "karma-webpack": "^4.0.2", 55 | "npm-run-all": "^4.1.5", 56 | "prettier": "^1.18.2", 57 | "puppeteer": "^2.0.0", 58 | "selenium-webdriver": "^4.0.0-alpha.5", 59 | "ts-jest": "^24.1.0", 60 | "ts-loader": "^6.2.1", 61 | "ts-node": "^8.4.1", 62 | "typescript": "^3.7.2", 63 | "webpack": "^4.41.2", 64 | "webpack-cli": "^3.3.10", 65 | "webpack-dev-server": "^3.9.0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/__tests__/example.karma.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { add } from "../add"; 3 | 4 | it("jasmine test example", () => { 5 | assert.equal(add(1, 2), 3); 6 | }); 7 | -------------------------------------------------------------------------------- /src/__tests__/example.test.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { add } from "../add"; 3 | 4 | it("example test", () => { 5 | assert.ok(true); 6 | assert.equal(add(1, 2), 3); 7 | }); 8 | -------------------------------------------------------------------------------- /src/__tests__/flaky-retry.test.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | 3 | jest.retryTimes(10); 4 | 5 | it("flaky", () => { 6 | assert.ok(Math.random() > 0.25); 7 | }); 8 | -------------------------------------------------------------------------------- /src/add.ts: -------------------------------------------------------------------------------- 1 | export function add(a: number, b: number): number { 2 | return a + b; 3 | } 4 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | const el = document.createElement("div"); 2 | el.innerHTML = "hello"; 3 | el.setAttribute("data-testid", "root"); 4 | document.body.appendChild(el); 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, 6 | "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | // "outDir": "./", /* Redirect output structure to the directory. */ 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | "strict": true /* Enable all strict type-checking options. */, 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | // "types": [], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HTMLPlugin = require("html-webpack-plugin"); 3 | module.exports = (_env, _argv) => ({ 4 | resolve: { 5 | extensions: [".js", ".ts"] 6 | }, 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.tsx?$/, 11 | use: [ 12 | { 13 | loader: "ts-loader", 14 | options: { 15 | transpileOnly: true 16 | } 17 | } 18 | ] 19 | } 20 | ] 21 | }, 22 | plugins: [ 23 | new HTMLPlugin({ template: path.join(__dirname, "src/index.html") }) 24 | ] 25 | }); 26 | --------------------------------------------------------------------------------