From 1841f3f0ed1dab74ace2263f88d5b59a86a66759 Mon Sep 17 00:00:00 2001 From: Jesse Jurman Date: Sun, 25 Jun 2017 01:11:08 -0400 Subject: [PATCH] Rollup & SSR, Release: 1.1.0 (#15) --- README.md | 18 ++++++------- configs/rollup.esm.config.js | 26 +++++++++++++++++++ configs/rollup.umd.config.js | 33 ++++++++++++++++++++++++ configs/testem.yml | 6 ++++- configs/webpack.config.js | 32 ----------------------- examples/ssr-example/index.js | 22 ++++++++++++++++ examples/ssr-example/server.js | 17 +++++++++++++ package.json | 33 ++++++++++++++++++++---- tests/specs/tram-spec.js | 46 ++++++++++++++++++++++------------ tests/testem.html | 1 - tram-one.js | 5 +++- 11 files changed, 173 insertions(+), 66 deletions(-) create mode 100644 configs/rollup.esm.config.js create mode 100644 configs/rollup.umd.config.js delete mode 100644 configs/webpack.config.js create mode 100644 examples/ssr-example/index.js create mode 100644 examples/ssr-example/server.js diff --git a/README.md b/README.md index 09ecc3f..ebf8d38 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ 🚋 Batteries Included View Framework ## Install -``` +```sh npm install tram-one --save ``` @@ -375,6 +375,9 @@ are combined, and the app is mounted onto the `selector`. `pathName` can be an initial path, if you don't want to check the browser's current path. +This method only works on the client. If you are running Tram on a server, then +use `.toString()`. + Note: setting `pathName` is great for testing, but prevents other routes from being reached on page reload. @@ -434,10 +437,10 @@ if you want to manually attach the HTMLNode that Tram-One builds to whatever. ### `app.toString(pathName, [state])` `app.toString` returns a string of the app for a given route and state. It has -the same interface at `app.toNode`, and basically just calls `.outerHTML` on that. +the same interface at `app.toNode`, and basically just calls `.outerHTML` (or +`toString` on the server) on the node. -This can be useful if you want to do server-sider rendering. Note, this really -hasn't been explored too much, so, milage may vary. +This can be useful if you want to do server-sider rendering or testing. ## Development @@ -451,10 +454,5 @@ If you decide to clone this repo, there are several commands included in the ## Todo +Check out our [Issues on Github](https://github.com/JRJurman/tram-one/issues). PRs welcome! - -- badges on README -- advertise build size -- source maps -- CI (probably with Circle-CI?) -- List Repositories with Example Apps diff --git a/configs/rollup.esm.config.js b/configs/rollup.esm.config.js new file mode 100644 index 0000000..08ffa60 --- /dev/null +++ b/configs/rollup.esm.config.js @@ -0,0 +1,26 @@ +import uglify from 'rollup-plugin-uglify' + +const babel = require('rollup-plugin-babel') +const filesize = require('rollup-plugin-filesize') + +const pkg = require('../package.json') +const external = Object.keys(pkg.dependencies) + +const plugins = [ + babel({ + presets: [ + 'es2015-rollup' + ] + }), + uglify(), + filesize() +] + +export default { + entry: 'tram-one.js', + external: external, + dest: pkg.main, + format: 'es', + plugins: plugins, + sourceMap: true +} diff --git a/configs/rollup.umd.config.js b/configs/rollup.umd.config.js new file mode 100644 index 0000000..aafb456 --- /dev/null +++ b/configs/rollup.umd.config.js @@ -0,0 +1,33 @@ +import uglify from 'rollup-plugin-uglify' + +const commonjs = require('rollup-plugin-commonjs') +const resolve = require('rollup-plugin-node-resolve') +const babel = require('rollup-plugin-babel') +const builtins = require('rollup-plugin-node-builtins') +const globals = require('rollup-plugin-node-globals') +const filesize = require('rollup-plugin-filesize') + +const pkg = require('../package.json') + +const plugins = [ + resolve({ main: true, preferBuiltins: true }), + commonjs(), + globals(), + builtins(), + babel({ + presets: [ + 'es2015-rollup' + ] + }), + uglify(), + filesize() +] + +export default { + entry: 'tram-one.js', + dest: pkg.browser, + format: 'umd', + plugins: plugins, + moduleName: 'tram-one', + sourceMap: true +} diff --git a/configs/testem.yml b/configs/testem.yml index b595c93..ac7136a 100644 --- a/configs/testem.yml +++ b/configs/testem.yml @@ -1,6 +1,10 @@ framework: jasmine launch_in_dev: - - phantomjs + - PhantomJS + - Node +launchers: + Node: + command: npm run test-server src_files: - tram-one.js - tests/specs/*.js diff --git a/configs/webpack.config.js b/configs/webpack.config.js deleted file mode 100644 index 116231f..0000000 --- a/configs/webpack.config.js +++ /dev/null @@ -1,32 +0,0 @@ -const webpack = require('webpack') - -module.exports = { - entry: './tram-one.js', - module: { - rules: [{ - use: { - loader: 'babel-loader', - options: { - presets: ['env'] - } - } - }] - }, - plugins: [ - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - }, - output: { - comments: false - } - }) - ], - output: { - filename: './dist/tram-one.js', - // export to AMD, CommonJS, or window - libraryTarget: 'umd', - // the name exported to window - library: 'tram-one' - } -} diff --git a/examples/ssr-example/index.js b/examples/ssr-example/index.js new file mode 100644 index 0000000..3d4c158 --- /dev/null +++ b/examples/ssr-example/index.js @@ -0,0 +1,22 @@ +const Tram = require('../../tram-one') +const app = new Tram() +const html = Tram.html() +const home = () => html` +
+

This is the Home Page

+
This is rendered on a server, and then served up to you!
+
We also have a number page here: /num +
+` +const num = (state) => html` +
+

This is a Number Page

+
This is rendered on a server, and then served up to you!
+
We can even take in stuff from the server, like this number: ${state.number}
+
+` + +app.addRoute('/', home) +app.addRoute('/number', num) + +module.exports = app diff --git a/examples/ssr-example/server.js b/examples/ssr-example/server.js new file mode 100644 index 0000000..244296d --- /dev/null +++ b/examples/ssr-example/server.js @@ -0,0 +1,17 @@ +const express = require('express') +const server = express() + +const app = require('./index') + +server.get('/', (req, res) => { + res.send(app.toString('/')) +}) + +server.get('/num', (req, res) => { + const number = Math.random() * 10 + res.send(app.toString('/number', {number})) +}) + +server.listen(5000, () => { + console.log('ssr express server running on port 5000!') +}) diff --git a/package.json b/package.json index a4c25f4..805a8e9 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,23 @@ { "name": "tram-one", - "version": "1.0.0", + "version": "1.1.0", "description": "🚋 Batteries Included View Framework", - "main": "dist/tram-one.js", - "files": ["dist/tram-one.js"], + "main": "dist/tram-one.esm.js", + "browser": "dist/tram-one.umd.js", + "files": [ + "dist/tram-one.esm.js", + "dist/tram-one.umd.js" + ], "scripts": { "lint": "eslint ./", "example": "node dev-scripts/example-selector.js", "examples": "npm run example", - "build": "webpack --config configs/webpack.config.js", - "test-build": "webpack --config configs/webpack.config.js && webpack --config configs/webpack.testem.config.js", + "build": "npm run build-esm && npm run build-umd", + "build-esm": "rollup -c configs/rollup.esm.config.js", + "build-umd": "rollup -c configs/rollup.umd.config.js", + "test-build": "npm run build && webpack --config configs/webpack.testem.config.js", "test-dev": "testem -f configs/testem.yml", + "test-server": "jasmine tests/specs/tram-spec.js", "test": "testem ci -f configs/testem.yml" }, "author": { @@ -32,14 +39,30 @@ "devDependencies": { "babel-core": "^6.25.0", "babel-loader": "^7.0.0", + "babel-plugin-external-helpers": "^6.22.0", "babel-preset-env": "^1.5.2", + "babel-preset-es2015": "^6.24.1", + "babel-preset-es2015-rollup": "^3.0.0", "eslint": "^3.19.0", "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.6.0", + "eslint-plugin-node": "^5.0.0", "eslint-plugin-promise": "^3.5.0", "eslint-plugin-standard": "^3.0.1", + "express": "^4.15.3", "inquirer": "^3.1.0", "internal-ip": "^1.2.0", + "jasmine": "^2.6.0", + "min-document": "^2.19.0", "opn": "^5.0.0", + "rollup": "^0.43.0", + "rollup-plugin-babel": "^2.7.1", + "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-filesize": "^1.4.2", + "rollup-plugin-node-builtins": "^2.1.2", + "rollup-plugin-node-globals": "^1.1.0", + "rollup-plugin-node-resolve": "^3.0.0", + "rollup-plugin-uglify": "^2.0.1", "testem": "^1.16.2", "webpack": "^2.6.1", "webpack-dev-server": "^2.4.5" diff --git a/tests/specs/tram-spec.js b/tests/specs/tram-spec.js index 748ab47..e213848 100644 --- a/tests/specs/tram-spec.js +++ b/tests/specs/tram-spec.js @@ -1,5 +1,15 @@ -const Tram = window['tram-one'] -const testemPath = window.location.pathname +const Tram = require('../../dist/tram-one.esm') + +const isBrowser = typeof window !== 'undefined' +const testemPath = isBrowser ? window.location.pathname : '/' +const document = isBrowser ? window.document : require('min-document') + +const stringify = (node) => { + if (node.outerHTML !== undefined) { + return node.outerHTML + } + return node.toString() +} describe('Tram', () => { let app @@ -23,14 +33,14 @@ describe('Tram', () => { app = new Tram() app.addRoute('/404', errorPage) - expect(app.toString('/')).toEqual(errorPage().outerHTML) + expect(app.toString('/')).toEqual(stringify(errorPage())) }) it('should take in a default route', () => { app = new Tram({defaultRoute: '/200'}) app.addRoute('/200', successPage) - expect(app.toString('/')).toEqual(successPage().outerHTML) + expect(app.toString('/')).toEqual(stringify(successPage())) }) it('should not always go to the default', () => { @@ -38,7 +48,7 @@ describe('Tram', () => { app.addRoute('/404', errorPage) app.addRoute('/200', successPage) - expect(app.toString('/200')).not.toEqual(errorPage().outerHTML) + expect(app.toString('/200')).not.toEqual(stringify(errorPage())) }) }) @@ -63,10 +73,10 @@ describe('Tram', () => { app.addRoute('/good', successPage) app.addRoute('/bad', errorPage) app.addRoute('/404', errorPage) - expect(app.toString('/')).toEqual(successPage().outerHTML) - expect(app.toString('/good')).toEqual(successPage().outerHTML) - expect(app.toString('/bad')).toEqual(errorPage().outerHTML) - expect(app.toString('/404')).toEqual(errorPage().outerHTML) + expect(app.toString('/')).toEqual(stringify(successPage())) + expect(app.toString('/good')).toEqual(stringify(successPage())) + expect(app.toString('/bad')).toEqual(stringify(errorPage())) + expect(app.toString('/404')).toEqual(stringify(errorPage())) }) it('should include the default state in app', () => { @@ -86,6 +96,8 @@ describe('Tram', () => { }) describe('start', () => { + if (!isBrowser) { return } + beforeEach(() => { const childDiv = document.createElement('div') childDiv.id = 'tram_test_container' @@ -120,6 +132,8 @@ describe('Tram', () => { }) describe('mount', () => { + if (!isBrowser) { return } + beforeEach(() => { const childDiv = document.createElement('div') childDiv.id = 'tram_test_container' @@ -136,9 +150,9 @@ describe('Tram', () => { app.addRoute('/', queryablePage) const target = document.getElementById('tram_test_container') - app.mount(target, '/') + app.mount(target, '/', undefined, document) const mountedTarget = document.querySelector(queryableSelector) - expect(mountedTarget.outerHTML).toEqual(queryablePage().outerHTML) + expect(mountedTarget.outerHTML).toEqual(stringify(queryablePage())) }) it('should use the default route', () => { @@ -149,7 +163,7 @@ describe('Tram', () => { const target = document.getElementById('tram_test_container') app.mount(target) const mountedTarget = document.querySelector(queryableSelector) - expect(mountedTarget.outerHTML).toEqual(queryablePage(200).outerHTML) + expect(mountedTarget.outerHTML).toEqual(stringify(queryablePage(200))) }) it('should attach the app to a selector', () => { @@ -158,7 +172,7 @@ describe('Tram', () => { app.addRoute('/', queryablePage) app.mount('#tram_test_container', '/') const mountedTarget = document.querySelector(queryableSelector) - expect(mountedTarget.outerHTML).toEqual(queryablePage().outerHTML) + expect(mountedTarget.outerHTML).toEqual(stringify(queryablePage())) }) it('should update the app on re-mount', () => { @@ -169,7 +183,7 @@ describe('Tram', () => { app.mount('#tram_test_container', '/') app.mount('#tram_test_container', '/200') const mountedTarget = document.querySelector(queryableSelector) - expect(mountedTarget.outerHTML).toEqual(queryablePage(200).outerHTML) + expect(mountedTarget.outerHTML).toEqual(stringify(queryablePage(200))) }) }) @@ -177,7 +191,7 @@ describe('Tram', () => { it('should resolve the path', () => { app = new Tram() app.addRoute('/', successPage) - expect(app.toNode('/').outerHTML).toEqual(successPage().outerHTML) + expect(stringify(app.toNode('/'))).toEqual(stringify(successPage())) }) it('should have the default state', () => { @@ -198,7 +212,7 @@ describe('Tram', () => { it('should return a string', () => { app = new Tram() app.addRoute('/404', errorPage) - expect(app.toString('/')).toEqual(errorPage().outerHTML) + expect(app.toString('/')).toEqual(stringify(errorPage())) }) }) diff --git a/tests/testem.html b/tests/testem.html index 11aa567..0167072 100644 --- a/tests/testem.html +++ b/tests/testem.html @@ -19,7 +19,6 @@ -
diff --git a/tram-one.js b/tram-one.js index 0484714..c94d3a0 100644 --- a/tram-one.js +++ b/tram-one.js @@ -61,7 +61,10 @@ class Tram { } toString(pathName, state) { - return this.toNode(pathName, state).outerHTML + if (typeof window !== 'undefined') { + return this.toNode(pathName, state).outerHTML + } + return this.toNode(pathName, state).toString() } static html(registry) {