Skip to content

Commit 44486bc

Browse files
fnlctrlposva
andauthored
refactor: error with enum types (vuejs#123)
* refactor error with enum codes * fix lint * rename error 'code' to 'type' * refactor * remove INVALID_ROUTE_MATCH * fix: lint * fix: remove ErrorTypeMessages in production build * fix: types * fix: add interface NavigationRedirectError * build: use similar config to vue * refactor: errors * build: add banner * refactor: delete old errors.ts * refactor: rename errors-new Co-authored-by: Eduardo San Martin Morote <[email protected]>
1 parent e480383 commit 44486bc

File tree

12 files changed

+342
-349
lines changed

12 files changed

+342
-349
lines changed

__tests__/errors.spec.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createRouter as newRouter, createMemoryHistory } from '../src'
2-
import { NavigationAborted, NavigationGuardRedirect } from '../src/errors'
2+
import { ErrorTypes } from '../src/errors'
33
import { components, tick } from './utils'
44
import { RouteRecord } from '../src/types'
55

@@ -47,9 +47,11 @@ describe('Errors', () => {
4747
try {
4848
await router.push('/foo')
4949
} catch (err) {
50-
expect(err).toBeInstanceOf(NavigationAborted)
50+
expect(err.type).toBe(ErrorTypes.NAVIGATION_ABORTED)
5151
}
52-
expect(onError).toHaveBeenCalledWith(expect.any(NavigationAborted))
52+
expect(onError).toHaveBeenCalledWith(
53+
expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
54+
)
5355
})
5456

5557
it('triggers erros caused by new navigations of a next(redirect) trigered by history', async () => {
@@ -69,12 +71,15 @@ describe('Errors', () => {
6971
expect(onError).toHaveBeenCalledTimes(2)
7072
expect(onError).toHaveBeenNthCalledWith(
7173
1,
72-
expect.any(NavigationGuardRedirect)
74+
expect.objectContaining({ type: ErrorTypes.NAVIGATION_GUARD_REDIRECT })
7375
)
7476
expect(onError.mock.calls[0]).toMatchObject([
7577
{ to: { params: { p: '1' } }, from: { fullPath: '/p/0' } },
7678
])
77-
expect(onError).toHaveBeenNthCalledWith(2, expect.any(NavigationAborted))
79+
expect(onError).toHaveBeenNthCalledWith(
80+
2,
81+
expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
82+
)
7883
expect(onError.mock.calls[1]).toMatchObject([
7984
{ to: { params: { p: '1' } }, from: { params: { p: 'other' } } },
8085
])
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

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

88
exports[`Router Matcher resolve LocationAsRelative throws if the current named route does not exists 1`] = `
9-
[NoRouteMatchError: No match for
10-
{"params":{"a":"foo"}}
9+
[Error: No match for
10+
{"params":{"a":"foo"}}
1111
while being at
1212
{"name":"home","params":{},"path":"/","meta":{}}]
1313
`;

__tests__/router.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fakePromise from 'faked-promise'
22
import { createRouter, createMemoryHistory, createWebHistory } from '../src'
3-
import { NavigationCancelled } from '../src/errors'
3+
import { ErrorTypes } from '../src/errors'
44
import { createDom, components, tick } from './utils'
55
import {
66
RouteRecord,
@@ -225,7 +225,7 @@ describe('Router', () => {
225225
try {
226226
await pA
227227
} catch (err) {
228-
expect(err).toBeInstanceOf(NavigationCancelled)
228+
expect(err.type).toBe(ErrorTypes.NAVIGATION_CANCELLED)
229229
}
230230
expect(router.currentRoute.value.fullPath).toBe('/p/b')
231231
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "4.0.0-alpha.3",
44
"main": "dist/vue-router.cjs.js",
55
"browser": "dist/vue-router.esm.js",
6-
"unpkg": "dist/vue-router.js",
6+
"unpkg": "dist/vue-router.global.js",
77
"module": "dist/vue-router.esm-bundler.js",
88
"typings": "dist/vue-router.d.ts",
99
"sideEffects": false,

rollup.config.js

+166-97
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,188 @@
1+
import path from 'path'
2+
import ts from 'rollup-plugin-typescript2'
13
import replace from '@rollup/plugin-replace'
24
import resolve from '@rollup/plugin-node-resolve'
35
import commonjs from 'rollup-plugin-commonjs'
4-
import ts from 'rollup-plugin-typescript2'
5-
import alias from '@rollup/plugin-alias'
6-
import { terser } from 'rollup-plugin-terser'
7-
import pkg from './package.json'
6+
7+
const pkg = require('./package.json')
8+
const name = pkg.name
89

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

15-
const exportName = 'VueRouter'
16-
17-
function createEntry(
18-
{
19-
format, // Rollup format (iife, umd, cjs, es)
20-
external = ['vue', '@vue/reactivity', '@vue/runtime-core'], // Rollup external option
21-
input = 'src/index.ts', // entry point
22-
env = 'development', // NODE_ENV variable
23-
minify = false,
24-
isBrowser = false, // produce a browser module version or not
25-
} = {
26-
input: 'src/index.ts',
27-
env: 'development',
28-
minify: false,
29-
isBrowser: false,
30-
}
31-
) {
32-
// force production mode when minifying
33-
if (minify) env = 'production'
34-
const isProductionBuild =
35-
process.env.__DEV__ === 'false' || env === 'production'
16+
// ensure TS checks only once for each build
17+
let hasTSChecked = false
3618

37-
const config = {
38-
input,
39-
plugins: [
40-
replace({
41-
__VERSION__: JSON.stringify(pkg.version),
42-
__DEV__:
43-
(format === 'es' && !isBrowser) || format === 'cjs'
44-
? // preserve to be handled by bundlers
45-
`process.env.NODE_ENV !== 'production'`
46-
: // hard coded dev/prod builds
47-
!isProductionBuild,
48-
}),
49-
alias({
50-
resolve: ['ts'],
51-
}),
52-
],
53-
output: {
54-
banner,
55-
file: 'dist/vue-router.other.js',
56-
format,
57-
globals: {
58-
'@vue/reactivity': 'Vue',
59-
'@vue/runtime-core': 'Vue',
60-
vue: 'Vue',
61-
},
62-
},
63-
}
19+
const outputConfigs = {
20+
// each file name has the format: `dist/${name}.${format}.js`
21+
// format being a key of this object
22+
'esm-bundler': {
23+
file: pkg.module,
24+
format: `es`,
25+
},
26+
cjs: {
27+
file: pkg.main,
28+
format: `cjs`,
29+
},
30+
global: {
31+
file: pkg.unpkg,
32+
format: `iife`,
33+
},
34+
esm: {
35+
file: pkg.browser,
36+
format: `es`,
37+
},
38+
}
6439

65-
if (format === 'iife') {
66-
// config.input = 'src/entries/iife.ts'
67-
config.output.file = pkg.unpkg
68-
config.output.name = exportName
69-
} else if (format === 'es') {
70-
config.output.file = isBrowser ? pkg.browser : pkg.module
71-
} else if (format === 'cjs') {
72-
config.output.file = 'dist/vue-router.cjs.js'
40+
const allFormats = Object.keys(outputConfigs)
41+
// in vue-router there are not that many
42+
const packageFormats = allFormats
43+
const packageConfigs = packageFormats.map(format =>
44+
createConfig(format, outputConfigs[format])
45+
)
46+
47+
// only add the production ready if we are bundling the options
48+
packageFormats.forEach(format => {
49+
if (format === 'cjs') {
50+
packageConfigs.push(createProductionConfig(format))
51+
} else if (format === 'global') {
52+
packageConfigs.push(createMinifiedConfig(format))
7353
}
54+
})
55+
56+
export default packageConfigs
7457

75-
if (!external) {
76-
config.plugins.push(resolve(), commonjs())
77-
} else {
78-
config.external = external
58+
function createConfig(format, output, plugins = []) {
59+
if (!output) {
60+
console.log(require('chalk').yellow(`invalid format: "${format}"`))
61+
process.exit(1)
7962
}
8063

81-
config.plugins.push(
82-
ts({
83-
// only check once, during the es version with browser (it includes external libs)
84-
check: format === 'es' && isBrowser && !minify,
85-
tsconfigOverride: {
86-
compilerOptions: {
87-
// same for d.ts files
88-
declaration: format === 'es' && isBrowser && !minify,
89-
module: 'esnext', // we need to override it because mocha requires this value to be commonjs
90-
target: format === 'iife' || format === 'cjs' ? 'es5' : 'esnext',
91-
},
64+
output.sourcemap = true
65+
output.banner = banner
66+
output.externalLiveBindings = false
67+
output.globals = { vue: 'Vue' }
68+
69+
const isProductionBuild = /\.prod\.js$/.test(output.file)
70+
const isGlobalBuild = format === 'global'
71+
const isRawESMBuild = format === 'esm'
72+
const isNodeBuild = format === 'cjs'
73+
const isBundlerESMBuild = /esm-bundler/.test(format)
74+
75+
if (isGlobalBuild) output.name = 'VueRouter'
76+
77+
const shouldEmitDeclarations = !hasTSChecked
78+
79+
const tsPlugin = ts({
80+
check: !hasTSChecked,
81+
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
82+
cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
83+
tsconfigOverride: {
84+
compilerOptions: {
85+
sourceMap: output.sourcemap,
86+
declaration: shouldEmitDeclarations,
87+
declarationMap: shouldEmitDeclarations,
9288
},
93-
})
94-
)
89+
exclude: ['__tests__', 'test-dts'],
90+
},
91+
})
92+
// we only need to check TS and generate declarations once for each build.
93+
// it also seems to run into weird issues when checking multiple times
94+
// during a single build.
95+
hasTSChecked = true
9596

96-
if (minify) {
97-
config.plugins.push(
98-
terser({
99-
module: format === 'es',
100-
// output: {
101-
// preamble: banner,
102-
// },
103-
})
104-
)
105-
config.output.file = config.output.file.replace(/\.js$/i, '.min.js')
97+
const external = ['vue']
98+
99+
const nodePlugins = [resolve(), commonjs()]
100+
101+
return {
102+
input: `src/index.ts`,
103+
// Global and Browser ESM builds inlines everything so that they can be
104+
// used alone.
105+
external,
106+
plugins: [
107+
tsPlugin,
108+
createReplacePlugin(
109+
isProductionBuild,
110+
isBundlerESMBuild,
111+
// isBrowserBuild?
112+
isGlobalBuild || isRawESMBuild || isBundlerESMBuild,
113+
isGlobalBuild,
114+
isNodeBuild
115+
),
116+
...nodePlugins,
117+
...plugins,
118+
],
119+
output,
120+
// onwarn: (msg, warn) => {
121+
// if (!/Circular/.test(msg)) {
122+
// warn(msg)
123+
// }
124+
// },
106125
}
126+
}
107127

108-
return config
128+
function createReplacePlugin(
129+
isProduction,
130+
isBundlerESMBuild,
131+
isBrowserBuild,
132+
isGlobalBuild,
133+
isNodeBuild
134+
) {
135+
const replacements = {
136+
__COMMIT__: `"${process.env.COMMIT}"`,
137+
__VERSION__: `"${pkg.version}"`,
138+
__DEV__: isBundlerESMBuild
139+
? // preserve to be handled by bundlers
140+
`(process.env.NODE_ENV !== 'production')`
141+
: // hard coded dev/prod builds
142+
!isProduction,
143+
// this is only used during tests
144+
__TEST__: isBundlerESMBuild ? `(process.env.NODE_ENV === 'test')` : false,
145+
// If the build is expected to run directly in the browser (global / esm builds)
146+
__BROWSER__: isBrowserBuild,
147+
// is targeting bundlers?
148+
__BUNDLER__: isBundlerESMBuild,
149+
__GLOBAL__: isGlobalBuild,
150+
// is targeting Node (SSR)?
151+
__NODE_JS__: isNodeBuild,
152+
}
153+
// allow inline overrides like
154+
//__RUNTIME_COMPILE__=true yarn build
155+
Object.keys(replacements).forEach(key => {
156+
if (key in process.env) {
157+
replacements[key] = process.env[key]
158+
}
159+
})
160+
return replace(replacements)
161+
}
162+
163+
function createProductionConfig(format) {
164+
return createConfig(format, {
165+
file: `dist/${name}.${format}.prod.js`,
166+
format: outputConfigs[format].format,
167+
})
109168
}
110169

111-
export default [
112-
// browser-friendly UMD build
113-
createEntry({ format: 'iife' }),
114-
createEntry({ format: 'iife', minify: true }),
115-
createEntry({ format: 'cjs' }),
116-
// TODO: prod vs env
117-
createEntry({ format: 'es' }),
118-
createEntry({ format: 'es', isBrowser: true }),
119-
]
170+
function createMinifiedConfig(format) {
171+
const { terser } = require('rollup-plugin-terser')
172+
return createConfig(
173+
format,
174+
{
175+
file: `dist/${name}.${format}.prod.js`,
176+
format: outputConfigs[format].format,
177+
},
178+
[
179+
terser({
180+
module: /^esm/.test(format),
181+
compress: {
182+
ecma: 2015,
183+
pure_getters: true,
184+
},
185+
}),
186+
]
187+
)
188+
}

0 commit comments

Comments
 (0)