diff --git a/docs/config.rst b/docs/config.rst index cb84e4690..267fef9dc 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -57,6 +57,9 @@ Example: "tilejson": { "format": "webp" } + }, + "remote": { + "style": "https://demotiles.maplibre.org/style.json" } }, "data": { @@ -209,7 +212,7 @@ Not used by default. Each item in this object defines one style (map). It can have the following options: -* ``style`` -- name of the style json file [required] +* ``style`` -- name of the style json file or url of a remote hosted style [required] * ``serve_rendered`` -- whether to render the raster tiles for this style or not * ``serve_data`` -- whether to allow access to the original tiles, sprites and required glyphs * ``tilejson`` -- properties to add to the TileJSON created for the raster data diff --git a/src/serve_rendered.js b/src/serve_rendered.js index 64804d7ef..a7092e625 100644 --- a/src/serve_rendered.js +++ b/src/serve_rendered.js @@ -1027,10 +1027,19 @@ export const serve_rendered = { * @param {object} params Parameters object. * @param {string} id ID of the item. * @param {object} programOpts - An object containing the program options + * @param {object} style pre-fetched/read StyleJSON object. * @param {Function} dataResolver Function to resolve data. * @returns {Promise} */ - add: async function (options, repo, params, id, programOpts, dataResolver) { + add: async function ( + options, + repo, + params, + id, + programOpts, + style, + dataResolver, + ) { const map = { renderers: [], renderersStatic: [], @@ -1040,7 +1049,7 @@ export const serve_rendered = { const { publicUrl, verbose } = programOpts; - let styleJSON; + const styleJSON = clone(style); /** * Creates a pool of renderers. * @param {number} ratio Pixel ratio @@ -1229,12 +1238,6 @@ export const serve_rendered = { const styleFile = params.style; const styleJSONPath = path.resolve(options.paths.styles, styleFile); - try { - styleJSON = JSON.parse(await fsp.readFile(styleJSONPath)); - } catch (e) { - console.log('Error parsing style file'); - return false; - } if (styleJSON.sprite) { if (!Array.isArray(styleJSON.sprite)) { diff --git a/src/serve_style.js b/src/serve_style.js index 51b03d3de..a9c96f64b 100644 --- a/src/serve_style.js +++ b/src/serve_style.js @@ -196,9 +196,10 @@ export const serve_style = { * @param {object} params Parameters object containing style path * @param {string} id ID of the style. * @param {object} programOpts - An object containing the program options + * @param {object} style pre-fetched/read StyleJSON object. * @param {Function} reportTiles Function for reporting tile sources. * @param {Function} reportFont Function for reporting font usage - * @returns {boolean} true if add is succesful + * @returns {boolean} true if add is successful */ add: function ( options, @@ -206,21 +207,14 @@ export const serve_style = { params, id, programOpts, + style, reportTiles, reportFont, ) { const { publicUrl } = programOpts; const styleFile = path.resolve(options.paths.styles, params.style); + const styleJSON = clone(style); - let styleFileData; - try { - styleFileData = fs.readFileSync(styleFile); // TODO: could be made async if this function was - } catch (e) { - console.log(`Error reading style file "${params.style}"`); - return false; - } - - const styleJSON = JSON.parse(styleFileData); const validationErrors = validateStyleMin(styleJSON); if (validationErrors.length > 0) { console.log(`The file "${params.style}" is not a valid style file:`); diff --git a/src/server.js b/src/server.js index 82a6490b0..dd09db538 100644 --- a/src/server.js +++ b/src/server.js @@ -178,10 +178,29 @@ async function start(opts) { * @param {object} item - The style configuration object. * @param {boolean} allowMoreData - Whether to allow adding more data sources. * @param {boolean} reportFonts - Whether to report fonts. - * @returns {void} + * @returns {Promise} */ - function addStyle(id, item, allowMoreData, reportFonts) { + async function addStyle(id, item, allowMoreData, reportFonts) { let success = true; + + let styleJSON; + try { + if (isValidHttpUrl(item.style)) { + const res = await fetch(item.style); + if (!res.ok) { + throw new Error(`fetch error ${res.status}`); + } + styleJSON = await res.json(); + } else { + const styleFile = path.resolve(options.paths.styles, item.style); + const styleFileData = await fs.promises.readFile(styleFile); + styleJSON = JSON.parse(styleFileData); + } + } catch (e) { + console.log(`Error getting style file "${item.style}"`); + return false; + } + if (item.serve_data !== false) { success = serve_style.add( options, @@ -189,6 +208,7 @@ async function start(opts) { item, id, opts, + styleJSON, (styleSourceId, protocol) => { let dataItemId; for (const id of Object.keys(data)) { @@ -246,6 +266,7 @@ async function start(opts) { item, id, opts, + styleJSON, function dataResolver(styleSourceId) { let fileType; let inputFile; @@ -271,6 +292,7 @@ async function start(opts) { item.serve_rendered = false; } } + return success; } for (const id of Object.keys(config.styles || {})) { @@ -279,8 +301,7 @@ async function start(opts) { console.log(`Missing "style" property for ${id}`); continue; } - - addStyle(id, item, true, true); + startupPromises.push(addStyle(id, item, true, true)); } startupPromises.push( serve_font(options, serving.fonts, opts).then((sub) => {