Hi, nice one ! It is reproducible when I use the laminar debs built from the WIP package here: https://salsa.debian.org/debian/laminar after these fixes: https://bugs.debian.org/919181#27
Once started, the laminar service dashboard should be reachable from localhost:8080 but it fails to load. If you open chromium inspector it reports: vue-router.min.js:10 Uncaught ReferenceError: require is not defined at vue-router.min.js:10 (anonymous) @ vue-router.min.js:10 app.js:746 Uncaught ReferenceError: Chart is not defined at app.js:746 (anonymous) @ app.js:746 Navigated to http://10.0.3.188:8080/ vue.min.js:1 You are running Vue in development mode. Make sure to turn on production mode when deploying for production. See more tips at https://vuejs.org/guide/deployment.html Interestingly, laminar package does not depend on libjs-vue-router because the file served from: http://10.0.3.188:8080/js/vue-router.min.js gets hard-coded in the /usr/sbin/laminard executable in at build time. Indeed libjs-vue-router is a mere build-dep for laminar package: https://salsa.debian.org/debian/laminar/blob/master/debian/control#L15 Currently it is hardcoding vue-router.common.js as vue-router.min.js: https://salsa.debian.org/debian/laminar/blob/master/debian/patches/0001-Patch-build-system-to-use-JS-libraries-from-Debian-p.patch#L29 which is wrong. I fixed the JS lib locations like this: diff --git a/debian/patches/0001-Patch-build-system-to-use-JS-libraries-from-Debian-p.patch b/debian/patches/0001-Patch-build-system-to-use-JS-libraries-from-Debian-p.patch index 0d6ca8f..e6ffdfe 100644 --- a/debian/patches/0001-Patch-build-system-to-use-JS-libraries-from-Debian-p.patch +++ b/debian/patches/0001-Patch-build-system-to-use-JS-libraries-from-Debian-p.patch @@ -26,11 +26,11 @@ index cf73a1b..d18dc65 100644 - css/bootstrap.min.css EXPECTED_MD5 5d5357cb3704e1f43a1f5bfed2aebf42) +file(DOWNLOAD file:///usr/share/javascript/vue/vue.min.js + js/vue.min.js) -+file(DOWNLOAD file:///usr/share/javascript/vue-router/vue-router.common.js ++file(DOWNLOAD file:///usr/lib/nodejs/vue-router/dist/vue-router.min.js + js/vue-router.min.js) -+file(DOWNLOAD file://usr/share/javascript/ansi_up/ansi_up.min.js ++file(DOWNLOAD file:///usr/share/javascript/ansi_up/ansi_up.min.js + js/ansi_up.js) -+file(DOWNLOAD file://usr/share/javascript/chart.js/Chart.min.js ++file(DOWNLOAD file:///usr/share/javascript/chart.js/Chart.min.js + js/Chart.min.js) +file(DOWNLOAD file://usr/share/javascript/bootstrap/css/bootstrap.min.css + css/bootstrap.min.css) (notice the three forward slashes after file:) This gets rid of the Chart error, unfortunately for vue-router.min.js, for that I just get a different error in chrome inspector: vue-router.min.js:791 Uncaught TypeError: Regexp is not a function at compileRouteRegex (vue-router.min.js:791) at addRouteRecord (vue-router.min.js:723) at vue-router.min.js:681 at Array.forEach (<anonymous>) at createRouteMap (vue-router.min.js:680) at createMatcher (vue-router.min.js:864) at new VueRouter (vue-router.min.js:1942) at app.js:796 compileRouteRegex @ vue-router.min.js:791 addRouteRecord @ vue-router.min.js:723 (anonymous) @ vue-router.min.js:681 createRouteMap @ vue-router.min.js:680 createMatcher @ vue-router.min.js:864 VueRouter @ vue-router.min.js:1942 (anonymous) @ app.js:796 Indeed comparing this file: https://unpkg.com/vue-router@3.0.2/dist/vue-router.js with the one packaged by us, they're different. I attach the diff: diff vue-router.js_unpkg vue-router.min.js_debian > diff Paolo
3c3 < * (c) 2018 Evan You --- > * (c) 2019 Evan You 7,10c7,12 < typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : < typeof define === 'function' && define.amd ? define(factory) : < (global.VueRouter = factory()); < }(this, (function () { 'use strict'; --- > typeof exports === 'object' && typeof module !== 'undefined' ? > module.exports = factory(require('path-to-regexp')) : > typeof define === 'function' && define.amd ? define(['path-to-regexp'], > factory) : > (global.VueRouter = factory(global.Regexp)); > }(this, (function (Regexp) { 'use strict'; > > Regexp = Regexp && Regexp.hasOwnProperty('default') ? Regexp['default'] : > Regexp; 21c23 < if ("development" !== 'production' && !condition) { --- > if ("production" !== 'production' && !condition) { 127c129 < } --- > }; 140,146c142 < { < warn( < false, < "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " + < "expecting an object, function or boolean." < ); < } --- > 177c173 < "development" !== 'production' && warn(false, e.message); --- > "production" !== 'production' && warn(false, e.message); 247a244 > 487c484 < } --- > }; 648,1080d644 < var isarray = Array.isArray || function (arr) { < return Object.prototype.toString.call(arr) == '[object Array]'; < }; < < /** < * Expose `pathToRegexp`. < */ < var pathToRegexp_1 = pathToRegexp; < var parse_1 = parse; < var compile_1 = compile; < var tokensToFunction_1 = tokensToFunction; < var tokensToRegExp_1 = tokensToRegExp; < < /** < * The main path matching regexp utility. < * < * @type {RegExp} < */ < var PATH_REGEXP = new RegExp([ < // Match escaped characters that would otherwise appear in future matches. < // This allows the user to escape special characters that won't transform. < '(\\\\.)', < // Match Express-style parameters and un-named parameters with a prefix < // and optional suffixes. Matches appear as: < // < // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined] < // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined] < // "/*" => ["/", undefined, undefined, undefined, undefined, "*"] < '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))' < ].join('|'), 'g'); < < /** < * Parse a string for the raw tokens. < * < * @param {string} str < * @param {Object=} options < * @return {!Array} < */ < function parse (str, options) { < var tokens = []; < var key = 0; < var index = 0; < var path = ''; < var defaultDelimiter = options && options.delimiter || '/'; < var res; < < while ((res = PATH_REGEXP.exec(str)) != null) { < var m = res[0]; < var escaped = res[1]; < var offset = res.index; < path += str.slice(index, offset); < index = offset + m.length; < < // Ignore already escaped sequences. < if (escaped) { < path += escaped[1]; < continue < } < < var next = str[index]; < var prefix = res[2]; < var name = res[3]; < var capture = res[4]; < var group = res[5]; < var modifier = res[6]; < var asterisk = res[7]; < < // Push the current path onto the tokens. < if (path) { < tokens.push(path); < path = ''; < } < < var partial = prefix != null && next != null && next !== prefix; < var repeat = modifier === '+' || modifier === '*'; < var optional = modifier === '?' || modifier === '*'; < var delimiter = res[2] || defaultDelimiter; < var pattern = capture || group; < < tokens.push({ < name: name || key++, < prefix: prefix || '', < delimiter: delimiter, < optional: optional, < repeat: repeat, < partial: partial, < asterisk: !!asterisk, < pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?') < }); < } < < // Match any characters still remaining. < if (index < str.length) { < path += str.substr(index); < } < < // If the path exists, push it onto the end. < if (path) { < tokens.push(path); < } < < return tokens < } < < /** < * Compile a string to a template function for the path. < * < * @param {string} str < * @param {Object=} options < * @return {!function(Object=, Object=)} < */ < function compile (str, options) { < return tokensToFunction(parse(str, options)) < } < < /** < * Prettier encoding of URI path segments. < * < * @param {string} < * @return {string} < */ < function encodeURIComponentPretty (str) { < return encodeURI(str).replace(/[\/?#]/g, function (c) { < return '%' + c.charCodeAt(0).toString(16).toUpperCase() < }) < } < < /** < * Encode the asterisk parameter. Similar to `pretty`, but allows slashes. < * < * @param {string} < * @return {string} < */ < function encodeAsterisk (str) { < return encodeURI(str).replace(/[?#]/g, function (c) { < return '%' + c.charCodeAt(0).toString(16).toUpperCase() < }) < } < < /** < * Expose a method for transforming tokens into the path function. < */ < function tokensToFunction (tokens) { < // Compile all the tokens into regexps. < var matches = new Array(tokens.length); < < // Compile all the patterns before compilation. < for (var i = 0; i < tokens.length; i++) { < if (typeof tokens[i] === 'object') { < matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$'); < } < } < < return function (obj, opts) { < var path = ''; < var data = obj || {}; < var options = opts || {}; < var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent; < < for (var i = 0; i < tokens.length; i++) { < var token = tokens[i]; < < if (typeof token === 'string') { < path += token; < < continue < } < < var value = data[token.name]; < var segment; < < if (value == null) { < if (token.optional) { < // Prepend partial segment prefixes. < if (token.partial) { < path += token.prefix; < } < < continue < } else { < throw new TypeError('Expected "' + token.name + '" to be defined') < } < } < < if (isarray(value)) { < if (!token.repeat) { < throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`') < } < < if (value.length === 0) { < if (token.optional) { < continue < } else { < throw new TypeError('Expected "' + token.name + '" to not be empty') < } < } < < for (var j = 0; j < value.length; j++) { < segment = encode(value[j]); < < if (!matches[i].test(segment)) { < throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`') < } < < path += (j === 0 ? token.prefix : token.delimiter) + segment; < } < < continue < } < < segment = token.asterisk ? encodeAsterisk(value) : encode(value); < < if (!matches[i].test(segment)) { < throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"') < } < < path += token.prefix + segment; < } < < return path < } < } < < /** < * Escape a regular expression string. < * < * @param {string} str < * @return {string} < */ < function escapeString (str) { < return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1') < } < < /** < * Escape the capturing group by escaping special characters and meaning. < * < * @param {string} group < * @return {string} < */ < function escapeGroup (group) { < return group.replace(/([=!:$\/()])/g, '\\$1') < } < < /** < * Attach the keys as a property of the regexp. < * < * @param {!RegExp} re < * @param {Array} keys < * @return {!RegExp} < */ < function attachKeys (re, keys) { < re.keys = keys; < return re < } < < /** < * Get the flags for a regexp from the options. < * < * @param {Object} options < * @return {string} < */ < function flags (options) { < return options.sensitive ? '' : 'i' < } < < /** < * Pull out keys from a regexp. < * < * @param {!RegExp} path < * @param {!Array} keys < * @return {!RegExp} < */ < function regexpToRegexp (path, keys) { < // Use a negative lookahead to match only capturing groups. < var groups = path.source.match(/\((?!\?)/g); < < if (groups) { < for (var i = 0; i < groups.length; i++) { < keys.push({ < name: i, < prefix: null, < delimiter: null, < optional: false, < repeat: false, < partial: false, < asterisk: false, < pattern: null < }); < } < } < < return attachKeys(path, keys) < } < < /** < * Transform an array into a regexp. < * < * @param {!Array} path < * @param {Array} keys < * @param {!Object} options < * @return {!RegExp} < */ < function arrayToRegexp (path, keys, options) { < var parts = []; < < for (var i = 0; i < path.length; i++) { < parts.push(pathToRegexp(path[i], keys, options).source); < } < < var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options)); < < return attachKeys(regexp, keys) < } < < /** < * Create a path regexp from string input. < * < * @param {string} path < * @param {!Array} keys < * @param {!Object} options < * @return {!RegExp} < */ < function stringToRegexp (path, keys, options) { < return tokensToRegExp(parse(path, options), keys, options) < } < < /** < * Expose a function for taking tokens and returning a RegExp. < * < * @param {!Array} tokens < * @param {(Array|Object)=} keys < * @param {Object=} options < * @return {!RegExp} < */ < function tokensToRegExp (tokens, keys, options) { < if (!isarray(keys)) { < options = /** @type {!Object} */ (keys || options); < keys = []; < } < < options = options || {}; < < var strict = options.strict; < var end = options.end !== false; < var route = ''; < < // Iterate over the tokens and create our regexp string. < for (var i = 0; i < tokens.length; i++) { < var token = tokens[i]; < < if (typeof token === 'string') { < route += escapeString(token); < } else { < var prefix = escapeString(token.prefix); < var capture = '(?:' + token.pattern + ')'; < < keys.push(token); < < if (token.repeat) { < capture += '(?:' + prefix + capture + ')*'; < } < < if (token.optional) { < if (!token.partial) { < capture = '(?:' + prefix + '(' + capture + '))?'; < } else { < capture = prefix + '(' + capture + ')?'; < } < } else { < capture = prefix + '(' + capture + ')'; < } < < route += capture; < } < } < < var delimiter = escapeString(options.delimiter || '/'); < var endsWithDelimiter = route.slice(-delimiter.length) === delimiter; < < // In non-strict mode we allow a slash at the end of match. If the path to < // match already ends with a slash, we remove it for consistency. The slash < // is valid at the end of a path match, not in the middle. This is important < // in non-ending mode, where "/test/" shouldn't match "/test//route". < if (!strict) { < route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?'; < } < < if (end) { < route += '$'; < } else { < // In non-ending mode, we need the capturing groups to match as much as < // possible by using a positive lookahead to the end or next path segment. < route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)'; < } < < return attachKeys(new RegExp('^' + route, flags(options)), keys) < } < < /** < * Normalize the given path string, returning a regular expression. < * < * An empty array can be passed in for the keys, which will hold the < * placeholder key descriptions. For example, using `/user/:id`, `keys` will < * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`. < * < * @param {(string|RegExp|Array)} path < * @param {(Array|Object)=} keys < * @param {Object=} options < * @return {!RegExp} < */ < function pathToRegexp (path, keys, options) { < if (!isarray(keys)) { < options = /** @type {!Object} */ (keys || options); < keys = []; < } < < options = options || {}; < < if (path instanceof RegExp) { < return regexpToRegexp(path, /** @type {!Array} */ (keys)) < } < < if (isarray(path)) { < return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options) < } < < return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options) < } < pathToRegexp_1.parse = parse_1; < pathToRegexp_1.compile = compile_1; < pathToRegexp_1.tokensToFunction = tokensToFunction_1; < pathToRegexp_1.tokensToRegExp = tokensToRegExp_1; < 1094c658 < (regexpCompileCache[path] = pathToRegexp_1.compile(path)); --- > (regexpCompileCache[path] = Regexp.compile(path)); 1097,1099d660 < { < warn(false, ("missing param for " + routeMsg + ": " + (e.message))); < } 1149,1157d709 < { < assert(path != null, "\"path\" is required in a route configuration."); < assert( < typeof route.component !== 'string', < "route config \"component\" for path: " + (String(path || name)) + " cannot be a " + < "string id. Use an actual component instead." < ); < } < 1191,1202d742 < { < if (route.name && !route.redirect && route.children.some(function (child) { return /^\/?$/.test(child.path); })) { < warn( < false, < "Named Route '" + (route.name) + "' has a default child route. " + < "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " + < "the default child route will not be rendered. Remove the name from " + < "this route and use the name of the default child route for named " + < "links instead." < ); < } < } 1240c780 < } else if ("development" !== 'production' && !matchAs) { --- > } else if ("production" !== 'production' && !matchAs) { 1251,1258c791 < var regex = pathToRegexp_1(path, [], pathToRegexpOptions); < { < var keys = Object.create(null); < regex.keys.forEach(function (key) { < warn(!keys[key.name], ("Duplicate param keys in route with path: \"" + path + "\"")); < keys[key.name] = true; < }); < } --- > var regex = Regexp(path, [], pathToRegexpOptions); 1270a804 > 1294,1296c828 < } else { < warn(false, "relative params navigation requires a current route."); < } --- > } else {} 1328d859 < 1352,1354d882 < { < warn(record, ("Route with name '" + name + "' does not exist")); < } 1404,1408d931 < { < warn( < false, ("invalid redirect option: " + (JSON.stringify(redirect))) < ); < } 1424,1427d946 < var targetRecord = nameMap[name]; < { < assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found.")); < } 1448,1450d966 < { < warn(false, ("invalid redirect option: " + (JSON.stringify(redirect)))); < } 1524a1041 > 1554,1558d1070 < { < assert(typeof behavior === 'function', "scrollBehavior must be a function"); < } < < // wait until re-render finishes before scrolling 1571,1573c1083 < { < assert(false, err.toString()); < } --- > 1761c1271 < "development" !== 'production' && warn(false, msg); --- > "production" !== 'production' && warn(false, msg); 2136a1647 > 2224a1736 > 2361a1874 > 2420,2421d1932 < < 2454,2456c1965 < { < assert(false, ("invalid mode: " + mode)); < } --- > 2477c1986 < "development" !== 'production' && assert( --- > "production" !== 'production' && assert( 2626a2136 > //# sourceMappingURL=vue-router.min.js.map