1
0
mirror of synced 2025-11-08 12:57:47 +00:00

Merge pull request #13 from bitjson/feature/browser

This commit is contained in:
Jason Dreyzehner
2017-03-01 02:04:04 -05:00
committed by GitHub
19 changed files with 1193 additions and 218 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules
build
test
src/**.js
coverage

View File

@@ -1,10 +1,13 @@
src
config
examples
test
tsconfig.json
tslint.json
.travis.yml
.github
build/temp
build/docs
coverage
.nyc_output

View File

@@ -49,10 +49,8 @@ yarn watch
which will build and watch the entire project for changes (to both the library source files and test source files). As you develop, you can add tests for new functionality which will initially fail before developing the new functionality. Each time you save, any changes will be rebuilt and retested.
Typescript builds on the left, tests run on the right:
<p align="center">
<img alt="Typescript and AVA watch task" src="https://cloud.githubusercontent.com/assets/904007/22908704/f4a83b20-f21d-11e6-8006-da6a851fb057.png">
<img alt="Typescript and AVA watch task" src="https://cloud.githubusercontent.com/assets/904007/23443884/c625d562-fdff-11e6-8f26-77bf75add240.png">
</p>
Since only changed files are rebuilt and retested, this workflow remains fast even for large projects.
@@ -148,9 +146,21 @@ yarn run info
```
## Notes
### Multiple builds (`main`, `module`, and `browser`)
The `src` of typescript-starter is compiled into three separate builds: `main`, `module`, and `browser`. The `main` build is [configured to use the CommonJS module system](https://github.com/bitjson/typescript-starter/blob/master/tsconfig.json#L8), while the `module` build [uses the new ES6 module system](https://github.com/bitjson/typescript-starter/blob/master/config/tsconfig.module.json). The browser build contains two bundles, an ES6 module (the preferred export) and a CommonJS bundle (primarily used for testing).
Because Node.js does not yet support the ES6 module system, Node.js projects which depend on typescript-starter will follow the `main` field in [`package.json`](https://github.com/bitjson/typescript-starter/blob/master/package.json). Tools which support the new system (like [Rollup](https://github.com/rollup/rollup)) will follow the `module` field, giving them the ability to statically analyze typescript-starter. When building for the browser, newer tools follow the `browser` field, which will resolve to the browser build's ES6 module.
### Browser libraries
This starter currently does **not** run tests in a browser ([AVA](https://github.com/avajs/ava) tests in Node exclusively). While the current testing system will be sufficient for most use cases, some projects will (also) need to implement a browser-based testing system like [karma-ava](https://github.com/avajs/karma-ava). (Pull requests welcome!)
While both the browser and the Node.js versions of the library are tested, this starter currently does **not** run the browser tests in a real browser ([AVA](https://github.com/avajs/ava) is currently Node-only). While the current testing system will be sufficient for most use cases, some projects will (also) need to implement a browser-based testing system like [karma-ava](https://github.com/avajs/karma-ava). (Pull requests welcome!)
Note: test coverage is only checked against the Node.js implementation. This is much simpler, and works well for libraries where the node and browser implementations have different dependencies and only minor adapter code. With only a few lines of differences (e.g. `src/adapters/crypto.browser.ts`), including those few lines in test coverage analysis usually isn't necessary.
### Building browser dependencies
This starter demonstrates importing and using a CommonJS module ([`hash.js`](https://github.com/indutny/hash.js)) for it's `hash256` method when built for the browser. See the `build:browser-deps` [package script](./package.json) and [rollup.config.js](./config/exports/rollup.config.js) for more details. Of course, your project likely does not need this dependency, so it can be removed. If your library doesn't need to bundle external dependencies for the browser, several other devDependencies can also be removed (`browserify`, `rollup-plugin-alias`, `rollup-plugin-commonjs`, `rollup-plugin-node-resolve`, etc).
### Dependency on `tslib`

View File

@@ -0,0 +1,41 @@
// this script watches the tests exported by typescript, copies them to the test directories, and modifies the require("PKG.NAME") statements to test each build
const cpx = require("cpx");
const separator = require("path").sep;
const Transform = require("stream").Transform;
const pkg = require('../../package');
const req = (path) => 'require("' + path + '")';
const pathUp = (levels) => Array.from(Array(levels), () => '../').join('');
// replace instances of pkg.name with the proper route to the build being tested
const makeTransform = (filePath, buildPath) => {
const buildPathParts = buildPath.split(separator);
// filePath includes build/main (-2), test/BUILD is 2 deep (+2),
// remove filename (-1). Total is length - 2
const pathToRoot = pathUp(filePath.split(separator).length - 1);
const placeholder = req(pkg.name);
return new Transform({
transform(chunk, encoding, done) {
const str = chunk.toString();
const parts = str.split(placeholder)
const newPath = req(pathToRoot + buildPath)
const result = parts.join(newPath);
this.push(result);
done();
}
});
}
// copy, then watch for changes to the tests
const testsFromRoot = 'build/main/**/*.spec.js';
const watchMode = process.argv.indexOf('-w') !== -1 ? true : false;
const browserTests = process.argv.indexOf('--no-browser') !== -1 ? true : false;
const task = watchMode ? cpx.watch : cpx.copy;
task(testsFromRoot, 'test/main', {
transform: (filePath) => makeTransform(filePath, pkg.main)
});
if (!browserTests) {
task(testsFromRoot, 'test/browser', {
transform: (filePath) => makeTransform(filePath, pkg.browser.replace('.js', '.cjs.js'))
});
}

View File

@@ -0,0 +1,21 @@
// rollup.config.js
import commonjs from 'rollup-plugin-commonjs';
import nodeResolve from 'rollup-plugin-node-resolve';
import alias from 'rollup-plugin-alias';
const substituteModulePaths = {
'crypto': 'build/module/adapters/crypto.browser.js',
'hash.js': 'build/temp/hash.js'
}
export default {
entry: 'build/module/index.js',
sourceMap: true,
plugins: [
alias(substituteModulePaths),
nodeResolve({
browser: true
}),
commonjs()
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "../../build/module",
"rootDir": "../../src",
"module": "es6",
"declaration": false
}
}

View File

@@ -1,12 +0,0 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"outDir": "../build/module",
"module": "es6",
"declaration": false
},
"exclude": [
"../node_modules/**",
"../src/**/*.spec.ts"
]
}

View File

@@ -5,19 +5,25 @@
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",
"module": "build/module/index.js",
"browser": "build/browser/index.js",
"repository": "https://github.com/bitjson/typescript-starter",
"author": "Jason Dreyzehner <jason@dreyzehner.com>",
"license": "MIT",
"scripts": {
"info": "npm-scripts-info",
"build": "trash build && tsc -p tsconfig.json && tsc -p config/tsconfig.module.json",
"build": "trash build && yarn build:main && yarn build:module && yarn build:browser-deps && yarn build:browser && yarn build:browser-cjs && yarn build:resolve-sourcemaps",
"build:main": "tsc -p tsconfig.json",
"build:module": "tsc -p config/exports/tsconfig.module.json",
"build:browser-deps": "mkdirp build/temp && browserify node_modules/hash.js/lib/hash.js --standalone hash -o build/temp/hash.js",
"build:browser": "rollup -c config/exports/rollup.config.js -f es -o build/browser/index.js",
"build:browser-cjs": "rollup -c config/exports/rollup.config.js -f cjs -o build/browser/index.cjs.js",
"build:resolve-sourcemaps": "sorcery -i build/browser/index.js && sorcery -i build/browser/index.cjs.js",
"build:tests": "trash test && node config/exports/build-tests.js",
"lint": "tslint src/**/*.ts",
"unit": "yarn build && nyc ava",
"unit": "yarn build && yarn build:tests && nyc ava",
"check-coverage": "nyc check-coverage --lines 100 --functions 100 --branches 100",
"test": "yarn lint && yarn unit && yarn check-coverage",
"watch": "trash build && multiview [yarn watch:build] [yarn watch:unit]",
"watch:build": "tsc -p tsconfig.json -w",
"watch:unit": "tsc -p tsconfig.json && ava --watch --verbose",
"watch": "yarn build && yarn build:tests -- --no-browser && concurrently -r --kill-others 'npm run --silent build:main -- -w' 'npm run --silent build:tests -- -w --no-browser' 'sleepms 2000 && ava --watch'",
"cov": "yarn unit && yarn html-coverage && opn coverage/index.html",
"html-coverage": "nyc report --reporter=html",
"send-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov",
@@ -46,18 +52,29 @@
},
"devDependencies": {
"@types/node": "^7.0.5",
"ava": "^0.18.1",
"ava": "^0.18.2",
"browserify": "^14.1.0",
"codecov": "^1.0.1",
"multiview": "^2.3.1",
"concurrently": "^3.3.0",
"cpx": "^1.5.0",
"hash.js": "^1.0.3",
"mkdirp": "^0.5.1",
"npm-scripts-info": "^0.3.6",
"nyc": "^10.0.0",
"opn-cli": "^3.1.0",
"rollup": "^0.41.4",
"rollup-plugin-alias": "^1.2.0",
"rollup-plugin-commonjs": "^7.0.0",
"rollup-plugin-node-resolve": "^2.0.0",
"rollup-watch": "^3.2.2",
"sleep-ms": "^2.0.1",
"sorcery": "^0.10.0",
"standard-version": "^4.0.0",
"trash-cli": "^1.4.0",
"tslint": "^4.0.2",
"tslint": "^4.5.1",
"tslint-config-standard": "^4.0.0",
"typedoc": "^0.5.5",
"typescript": "^2.2.0"
"typedoc": "^0.5.7",
"typescript": "^2.2.1"
},
"keywords": [
"async",
@@ -82,18 +99,18 @@
],
"nyc": {
"exclude": [
"**/*.spec.js"
"**/*.spec.js",
"build/browser/**"
]
},
"ava": {
"files": [
"build/main/**/*.spec.js"
],
"source": [
"build/main/**/*"
"test/**/*.js",
"build/**/*.js",
"!build/**/*.spec.js"
]
},
"dependencies": {
"tslib": "^1.5.0"
"tslib": "^1.6.0"
}
}

View File

@@ -0,0 +1,12 @@
// Must first be built by browserify.
// https://github.com/rollup/rollup-plugin-commonjs/issues/105#issuecomment-281917166
import hash from 'hash.js'
/**
* Simulate the Node.js crypto.createHash function using hash.js' implementation.
* @internal
* @hidden (TypeDoc currently doesn't understand @internal)
*/
export function createHash (algorithm: 'sha256') {
return hash.sha256()
}

View File

@@ -1,8 +0,0 @@
import { test } from 'ava'
import * as lib from './'
test('functions can be used without es imports', (t) => {
t.true(typeof lib.double === 'function')
t.true(typeof lib.power === 'function')
t.true(typeof lib.asyncABC === 'function')
})

View File

@@ -1,2 +1,3 @@
export * from './lib/numberOps'
export * from './lib/asyncOps'
export * from './lib/async'
export * from './lib/hash'
export * from './lib/number'

View File

@@ -1,5 +1,5 @@
import { test } from 'ava'
import { asyncABC } from '../'
import { asyncABC } from 'typescript-starter'
test('getABC', async t => {
t.deepEqual(await asyncABC(), ['a','b', 'c'])

6
src/lib/hash.spec.ts Normal file
View File

@@ -0,0 +1,6 @@
import { test } from 'ava'
import { sha256 } from 'typescript-starter'
test('sha256', t => {
t.deepEqual(sha256('test'), '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08')
})

17
src/lib/hash.ts Normal file
View File

@@ -0,0 +1,17 @@
import { createHash } from 'crypto'
/**
* Calculate the sha256 digest of a string. On Node.js, this will use the native module, in the browser, it will fall back to a pure javascript implementation.
*
* ### Example (es imports)
* ```js
* import { sha256 } from 'typescript-starter'
* sha256('test')
* // => '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
* ```
*
* @returns sha256 message digest
*/
export function sha256 (message: string) {
return createHash('sha256').update(message).digest('hex')
}

View File

@@ -1,5 +1,5 @@
import { test } from 'ava'
import { double, power } from '../'
import { double, power } from 'typescript-starter'
test('double', t => {
t.deepEqual(double(2), 4)

View File

@@ -1,5 +1,5 @@
{
"extends": "./config/tsconfig.flexible",
"extends": "./config/tsconfig.flexible", // also available: "./config/tsconfig.strict"
"compilerOptions": {
"target": "es6",
"outDir": "build/main",
@@ -17,7 +17,11 @@
],
"types" : [
"node"
]
],
"baseUrl": ".", // required for "paths"
"paths": {
"typescript-starter": ["src/index.ts"] // write tests without relative paths
}
},
"include": [
"src/**/*.ts"

1197
yarn.lock

File diff suppressed because it is too large Load Diff