Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor error with enum codes #123

Merged
merged 16 commits into from
Mar 18, 2020
15 changes: 10 additions & 5 deletions __tests__/errors.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createRouter as newRouter, createMemoryHistory } from '../src'
import { NavigationAborted, NavigationGuardRedirect } from '../src/errors'
import { ErrorTypes } from '../src/errors'
import { components, tick } from './utils'
import { RouteRecord } from '../src/types'

Expand Down Expand Up @@ -47,9 +47,11 @@ describe('Errors', () => {
try {
await router.push('/foo')
} catch (err) {
expect(err).toBeInstanceOf(NavigationAborted)
expect(err.type).toBe(ErrorTypes.NAVIGATION_ABORTED)
}
expect(onError).toHaveBeenCalledWith(expect.any(NavigationAborted))
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
)
})

it('triggers erros caused by new navigations of a next(redirect) trigered by history', async () => {
Expand All @@ -69,12 +71,15 @@ describe('Errors', () => {
expect(onError).toHaveBeenCalledTimes(2)
expect(onError).toHaveBeenNthCalledWith(
1,
expect.any(NavigationGuardRedirect)
expect.objectContaining({ type: ErrorTypes.NAVIGATION_GUARD_REDIRECT })
)
expect(onError.mock.calls[0]).toMatchObject([
{ to: { params: { p: '1' } }, from: { fullPath: '/p/0' } },
])
expect(onError).toHaveBeenNthCalledWith(2, expect.any(NavigationAborted))
expect(onError).toHaveBeenNthCalledWith(
2,
expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
)
expect(onError.mock.calls[1]).toMatchObject([
{ to: { params: { p: '1' } }, from: { params: { p: 'other' } } },
])
Expand Down
8 changes: 4 additions & 4 deletions __tests__/matcher/__snapshots__/resolve.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Router Matcher resolve LocationAsName throws if the named route does not exists 1`] = `
[NoRouteMatchError: No match for
{"name":"Home"}]
[Error: No match for
{"name":"Home"}]
`;

exports[`Router Matcher resolve LocationAsRelative throws if the current named route does not exists 1`] = `
[NoRouteMatchError: No match for
{"params":{"a":"foo"}}
[Error: No match for
{"params":{"a":"foo"}}
while being at
{"name":"home","params":{},"path":"/","meta":{}}]
`;
4 changes: 2 additions & 2 deletions __tests__/router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fakePromise from 'faked-promise'
import { createRouter, createMemoryHistory, createWebHistory } from '../src'
import { NavigationCancelled } from '../src/errors'
import { ErrorTypes } from '../src/errors'
import { createDom, components, tick } from './utils'
import {
RouteRecord,
Expand Down Expand Up @@ -225,7 +225,7 @@ describe('Router', () => {
try {
await pA
} catch (err) {
expect(err).toBeInstanceOf(NavigationCancelled)
expect(err.type).toBe(ErrorTypes.NAVIGATION_CANCELLED)
}
expect(router.currentRoute.value.fullPath).toBe('/p/b')
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "4.0.0-alpha.3",
"main": "dist/vue-router.cjs.js",
"browser": "dist/vue-router.esm.js",
"unpkg": "dist/vue-router.js",
"unpkg": "dist/vue-router.global.js",
"module": "dist/vue-router.esm-bundler.js",
"typings": "dist/vue-router.d.ts",
"sideEffects": false,
Expand Down
263 changes: 166 additions & 97 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,188 @@
import path from 'path'
import ts from 'rollup-plugin-typescript2'
import replace from '@rollup/plugin-replace'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import ts from 'rollup-plugin-typescript2'
import alias from '@rollup/plugin-alias'
import { terser } from 'rollup-plugin-terser'
import pkg from './package.json'

const pkg = require('./package.json')
const name = pkg.name

const banner = `/*!
* ${pkg.name} v${pkg.version}
* (c) ${new Date().getFullYear()} Eduardo San Martin Morote
* @license MIT
*/`

const exportName = 'VueRouter'

function createEntry(
{
format, // Rollup format (iife, umd, cjs, es)
external = ['vue', '@vue/reactivity', '@vue/runtime-core'], // Rollup external option
input = 'src/index.ts', // entry point
env = 'development', // NODE_ENV variable
minify = false,
isBrowser = false, // produce a browser module version or not
} = {
input: 'src/index.ts',
env: 'development',
minify: false,
isBrowser: false,
}
) {
// force production mode when minifying
if (minify) env = 'production'
const isProductionBuild =
process.env.__DEV__ === 'false' || env === 'production'
// ensure TS checks only once for each build
let hasTSChecked = false

const config = {
input,
plugins: [
replace({
__VERSION__: JSON.stringify(pkg.version),
__DEV__:
(format === 'es' && !isBrowser) || format === 'cjs'
? // preserve to be handled by bundlers
`process.env.NODE_ENV !== 'production'`
: // hard coded dev/prod builds
!isProductionBuild,
}),
alias({
resolve: ['ts'],
}),
],
output: {
banner,
file: 'dist/vue-router.other.js',
format,
globals: {
'@vue/reactivity': 'Vue',
'@vue/runtime-core': 'Vue',
vue: 'Vue',
},
},
}
const outputConfigs = {
// each file name has the format: `dist/${name}.${format}.js`
// format being a key of this object
'esm-bundler': {
file: pkg.module,
format: `es`,
},
cjs: {
file: pkg.main,
format: `cjs`,
},
global: {
file: pkg.unpkg,
format: `iife`,
},
esm: {
file: pkg.browser,
format: `es`,
},
}

if (format === 'iife') {
// config.input = 'src/entries/iife.ts'
config.output.file = pkg.unpkg
config.output.name = exportName
} else if (format === 'es') {
config.output.file = isBrowser ? pkg.browser : pkg.module
} else if (format === 'cjs') {
config.output.file = 'dist/vue-router.cjs.js'
const allFormats = Object.keys(outputConfigs)
// in vue-router there are not that many
const packageFormats = allFormats
const packageConfigs = packageFormats.map(format =>
createConfig(format, outputConfigs[format])
)

// only add the production ready if we are bundling the options
packageFormats.forEach(format => {
if (format === 'cjs') {
packageConfigs.push(createProductionConfig(format))
} else if (format === 'global') {
packageConfigs.push(createMinifiedConfig(format))
}
})

export default packageConfigs

if (!external) {
config.plugins.push(resolve(), commonjs())
} else {
config.external = external
function createConfig(format, output, plugins = []) {
if (!output) {
console.log(require('chalk').yellow(`invalid format: "${format}"`))
process.exit(1)
}

config.plugins.push(
ts({
// only check once, during the es version with browser (it includes external libs)
check: format === 'es' && isBrowser && !minify,
tsconfigOverride: {
compilerOptions: {
// same for d.ts files
declaration: format === 'es' && isBrowser && !minify,
module: 'esnext', // we need to override it because mocha requires this value to be commonjs
target: format === 'iife' || format === 'cjs' ? 'es5' : 'esnext',
},
output.sourcemap = true
output.banner = banner
output.externalLiveBindings = false
output.globals = { vue: 'Vue' }

const isProductionBuild = /\.prod\.js$/.test(output.file)
const isGlobalBuild = format === 'global'
const isRawESMBuild = format === 'esm'
const isNodeBuild = format === 'cjs'
const isBundlerESMBuild = /esm-bundler/.test(format)

if (isGlobalBuild) output.name = 'VueRouter'

const shouldEmitDeclarations = !hasTSChecked

const tsPlugin = ts({
check: !hasTSChecked,
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
tsconfigOverride: {
compilerOptions: {
sourceMap: output.sourcemap,
declaration: shouldEmitDeclarations,
declarationMap: shouldEmitDeclarations,
},
})
)
exclude: ['__tests__', 'test-dts'],
},
})
// we only need to check TS and generate declarations once for each build.
// it also seems to run into weird issues when checking multiple times
// during a single build.
hasTSChecked = true

if (minify) {
config.plugins.push(
terser({
module: format === 'es',
// output: {
// preamble: banner,
// },
})
)
config.output.file = config.output.file.replace(/\.js$/i, '.min.js')
const external = ['vue']

const nodePlugins = [resolve(), commonjs()]

return {
input: `src/index.ts`,
// Global and Browser ESM builds inlines everything so that they can be
// used alone.
external,
plugins: [
tsPlugin,
createReplacePlugin(
isProductionBuild,
isBundlerESMBuild,
// isBrowserBuild?
isGlobalBuild || isRawESMBuild || isBundlerESMBuild,
isGlobalBuild,
isNodeBuild
),
...nodePlugins,
...plugins,
],
output,
// onwarn: (msg, warn) => {
// if (!/Circular/.test(msg)) {
// warn(msg)
// }
// },
}
}

return config
function createReplacePlugin(
isProduction,
isBundlerESMBuild,
isBrowserBuild,
isGlobalBuild,
isNodeBuild
) {
const replacements = {
__COMMIT__: `"${process.env.COMMIT}"`,
__VERSION__: `"${pkg.version}"`,
__DEV__: isBundlerESMBuild
? // preserve to be handled by bundlers
`(process.env.NODE_ENV !== 'production')`
: // hard coded dev/prod builds
!isProduction,
// this is only used during tests
__TEST__: isBundlerESMBuild ? `(process.env.NODE_ENV === 'test')` : false,
// If the build is expected to run directly in the browser (global / esm builds)
__BROWSER__: isBrowserBuild,
// is targeting bundlers?
__BUNDLER__: isBundlerESMBuild,
__GLOBAL__: isGlobalBuild,
// is targeting Node (SSR)?
__NODE_JS__: isNodeBuild,
}
// allow inline overrides like
//__RUNTIME_COMPILE__=true yarn build
Object.keys(replacements).forEach(key => {
if (key in process.env) {
replacements[key] = process.env[key]
}
})
return replace(replacements)
}

function createProductionConfig(format) {
return createConfig(format, {
file: `dist/${name}.${format}.prod.js`,
format: outputConfigs[format].format,
})
}

export default [
// browser-friendly UMD build
createEntry({ format: 'iife' }),
createEntry({ format: 'iife', minify: true }),
createEntry({ format: 'cjs' }),
// TODO: prod vs env
createEntry({ format: 'es' }),
createEntry({ format: 'es', isBrowser: true }),
]
function createMinifiedConfig(format) {
const { terser } = require('rollup-plugin-terser')
return createConfig(
format,
{
file: `dist/${name}.${format}.prod.js`,
format: outputConfigs[format].format,
},
[
terser({
module: /^esm/.test(format),
compress: {
ecma: 2015,
pure_getters: true,
},
}),
]
)
}
Loading