diff --git a/README.md b/README.md index 0e7123a..468986d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,30 @@ npm install svelte-sitemap --save-dev ## Usage -> Use this library as a `postbuild` hook in your `package.json` file. +### Config file method (recommended) + +Create config file `svelte-sitemap.cjs` in the root of your project: + +`svelte-sitemap.cjs` + +```js +module.exports = { + domain: 'https://www.example.com' + // ...more options +}; +``` + +Add `svelte-sitemap` as your postbuild script in `package.json` file: + +`package.json` + +```json +{ + "postbuild": "npx svelte-sitemap" +} +``` + +### Alternative 1: CLI method File: `package.json` @@ -35,7 +58,7 @@ File: `package.json` It scans your routes in `build/` folder and generates `build/sitemap.xml` file. -### Alternative usage: TypeScript or JavaScript method +### Alternative 2: TypeScript or JavaScript method > Sometimes it can be useful to call the script directly from JavaScript or TypeScript. Of course there is also this option, but in most cases you will need the [CLI method](#cli-method-recommended) as a postbuild hook. @@ -44,11 +67,35 @@ File `my-script.js`: ```typescript import { createSitemap } from 'svelte-sitemap/src/index.js'; -createSitemap('https://example.com', { debug: true }); +createSitemap({ domain: 'https://example.com', debug: true }); ``` And now you can run your script like this: `node my-script.js` +## Example + +Use this library as a `postbuild` hook in your `package.json` with config file `svelte-sitemap.cjs` in your project root. + +File: `package.json` + +```json +{ + "name": "my-project", + "scripts": { + "postbuild": "npx svelte-sitemap" + } +} +``` + +File: `svelte-sitemap.cjs` + +```typescript +module.exports = { + domain: 'https://www.example.com', + trailingSlashes: true +}; +``` + ## ⚙️ Options | Option | Description | Default | Example | @@ -136,6 +183,7 @@ yarn demo - svelte-sitemap is workaround for [this official SvelteKit issue](https://github.com/sveltejs/kit/issues/1142) - Brand new version is inspired by [Richard's article](https://r-bt.com/learning/sveltekit-sitemap/) - Thanks to [@auderer](https://github.com/auderer) because [his issue](https://github.com/bartholomej/svelte-sitemap/issues/1) changed the direction of this library +- Config files inspired by [next-sitemap](https://github.com/iamvishnusankar/next-sitemap) ## 📝 License diff --git a/demo.ts b/demo.ts index a554154..5508b59 100644 --- a/demo.ts +++ b/demo.ts @@ -1,3 +1,3 @@ import { createSitemap } from './src/index'; -createSitemap('https://example.com/', { debug: false, resetTime: true }); +createSitemap({ domain: 'https://bartweb.cz', debug: false, resetTime: true, outDir: 'build' }); diff --git a/index.ts b/index.ts index ae5ad67..58470d7 100644 --- a/index.ts +++ b/index.ts @@ -2,13 +2,21 @@ import minimist from 'minimist'; import { version } from './package.json'; +import { loadConfig, withDefaultConfig } from './src/helpers/config'; +import { cliColors } from './src/helpers/vars.helper'; import { createSitemap } from './src/index'; -import { ChangeFreq, Options } from './src/interfaces/global.interface'; +import { ChangeFreq, OptionsSvelteSitemap } from './src/interfaces/global.interface'; +import { APP_NAME, CONFIG_FILE } from './src/vars'; + +console.log(cliColors.cyanAndBold, `> Using ${APP_NAME}`); const REPO_URL = 'https://github.com/bartholomej/svelte-sitemap'; let stop = false; +// Load svelte-sitemap.cjs +const config = loadConfig(CONFIG_FILE); + const args = minimist(process.argv.slice(2), { string: ['domain', 'out-dir', 'ignore', 'change-freq'], boolean: ['attribution', 'reset-time', 'trailing-slashes', 'debug', 'version'], @@ -57,12 +65,16 @@ if (args.help || args.version === '' || args.version === true) { log(' --debug Debug mode'); log(' '); process.exit(args.help ? 0 : 1); -} else if (!args.domain) { +} else if (!config.domain && !args.domain) { console.log( `⚠ svelte-sitemap: --domain argument is required.\n\nSee instructions: ${REPO_URL}\n\nExample:\n\n svelte-sitemap --domain https://mydomain.com\n` ); process.exit(0); -} else if (!args.domain.includes('http')) { +} else if ( + // (config.domain || args.domain) && + !config.domain?.includes('http') && + !args.domain?.includes('http') +) { console.log( `⚠ svelte-sitemap: --domain argument must starts with https://\n\nSee instructions: ${REPO_URL}\n\nExample:\n\n svelte-sitemap --domain https://mydomain.com\n` ); @@ -81,15 +93,30 @@ if (args.help || args.version === '' || args.version === true) { const ignore: string = args['ignore']; const attribution: boolean = args['attribution'] === '' || args['attribution'] === false ? false : true; - const options: Options = { + + const optionsCli: OptionsSvelteSitemap = { debug, resetTime, changeFreq, outDir, + domain, attribution, ignore, trailingSlashes }; - createSitemap(domain, options); + // Config file is preferred + if (config && Object.keys(config).length === 0) { + console.log( + cliColors.cyanAndBold, + ` ✔ Using CLI options. Config file ${CONFIG_FILE} not found.` + ); + createSitemap(optionsCli); + } else { + console.log( + cliColors.green, + ` ✔ Loading config from ${CONFIG_FILE}. CLI options are ignored now.` + ); + createSitemap(withDefaultConfig(config)); + } } diff --git a/package.json b/package.json index 02ddb26..4af393e 100644 --- a/package.json +++ b/package.json @@ -76,4 +76,4 @@ "node": ">= 14.17.0" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/src/helpers/config.ts b/src/helpers/config.ts new file mode 100644 index 0000000..ee1eb95 --- /dev/null +++ b/src/helpers/config.ts @@ -0,0 +1,30 @@ +import { OptionsSvelteSitemap } from '../interfaces/global.interface'; +import { OUT_DIR } from './../vars'; +import { loadFile } from './file'; + +export const loadConfig = (path: string): OptionsSvelteSitemap => { + const baseConfig = loadFile(path); + return baseConfig!; +}; + +export const defaultConfig: OptionsSvelteSitemap = { + debug: false, + changeFreq: null, + resetTime: false, + outDir: OUT_DIR, + attribution: true, + ignore: null, + trailingSlashes: false, + domain: null +}; + +export const updateConfig = ( + currConfig: OptionsSvelteSitemap, + newConfig: OptionsSvelteSitemap +): OptionsSvelteSitemap => { + return { ...currConfig, ...newConfig }; +}; + +export const withDefaultConfig = (config: OptionsSvelteSitemap): OptionsSvelteSitemap => { + return updateConfig(defaultConfig, config); +}; diff --git a/src/helpers/file.ts b/src/helpers/file.ts new file mode 100644 index 0000000..3b2fe89 --- /dev/null +++ b/src/helpers/file.ts @@ -0,0 +1,15 @@ +import { existsSync } from 'fs'; +import { resolve } from 'path'; + +export const loadFile = (fileName: string, throwError = true): T => { + const filePath = resolve(resolve(process.cwd(), fileName)); + + if (existsSync(filePath)) { + return require(filePath); + } + + if (throwError) { + new Error(`${filePath} does not exist.`); + } + return null; +}; diff --git a/src/helpers/global.helper.ts b/src/helpers/global.helper.ts index 1f9d9ca..7a9bc67 100644 --- a/src/helpers/global.helper.ts +++ b/src/helpers/global.helper.ts @@ -3,7 +3,7 @@ import fs from 'fs'; import { create } from 'xmlbuilder2'; import { version } from '../../package.json'; import { changeFreq, ChangeFreq, Options, PagesJson } from '../interfaces/global.interface'; -import { APP_NAME, OUT_DIR } from '../vars'; +import { OUT_DIR } from '../vars'; import { cliColors, errorMsgFolder, @@ -40,15 +40,13 @@ export const removeHtml = (fileName: string) => { }; export async function prepareData(domain: string, options?: Options): Promise { - console.log(cliColors.cyanAndBold, `> Using ${APP_NAME}`); - const FOLDER = options?.outDir ?? OUT_DIR; const ignore = prepareIgnored(options?.ignore, options?.outDir); const changeFreq = prepareChangeFreq(options); const pages: string[] = await fg(`${FOLDER}/**/*.html`, { ignore }); - const results = pages.map((page) => { + const results: PagesJson[] = pages.map((page) => { return { page: getUrl(page, domain, options), changeFreq: changeFreq, diff --git a/src/helpers/vars.helper.ts b/src/helpers/vars.helper.ts index 3efd1e0..f4c9b36 100644 --- a/src/helpers/vars.helper.ts +++ b/src/helpers/vars.helper.ts @@ -5,7 +5,7 @@ export const cliColors = { }; export const successMsg = (outDir: string) => - ` ✔ done. Check your new sitemap here: ./${outDir}/sitemap.xml`; + ` ✔ Done! Check your new sitemap here: ./${outDir}/sitemap.xml`; export const errorMsgWrite = (outDir: string) => ` × File '${outDir}/sitemap.xml' could not be created.`; diff --git a/src/index.ts b/src/index.ts index f64f860..6036e50 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,14 @@ import { prepareData, writeSitemap } from './helpers/global.helper'; import { cliColors, errorMsgWrite } from './helpers/vars.helper'; -import { Options } from './interfaces/global.interface'; -import { DOMAIN, OUT_DIR } from './vars'; +import { OptionsSvelteSitemap } from './interfaces/global.interface'; +import { OUT_DIR } from './vars'; -export const createSitemap = async (domain: string = DOMAIN, options?: Options): Promise => { +export const createSitemap = async (options: OptionsSvelteSitemap): Promise => { if (options?.debug) { console.log('OPTIONS', options); } - const json = await prepareData(domain, options); + const json = await prepareData(options.domain, options); if (options?.debug) { console.log('RESULT', json); diff --git a/src/interfaces/global.interface.ts b/src/interfaces/global.interface.ts index 1a283c4..3fe60bf 100644 --- a/src/interfaces/global.interface.ts +++ b/src/interfaces/global.interface.ts @@ -13,6 +13,10 @@ export interface Options { trailingSlashes?: boolean; } +export interface OptionsSvelteSitemap extends Options { + domain: string; +} + export interface PagesJson { page: string; changeFreq?: ChangeFreq; diff --git a/src/vars.ts b/src/vars.ts index e81fac1..7eec07b 100644 --- a/src/vars.ts +++ b/src/vars.ts @@ -1,9 +1,7 @@ -import { Options } from './interfaces/global.interface'; - export const APP_NAME = 'svelte-sitemap'; export const DOMAIN = 'https://example.com'; -export const OPTIONS: Options = { resetTime: false, debug: false, changeFreq: 'weekly' }; - export const OUT_DIR = 'build'; + +export const CONFIG_FILE = 'svelte-sitemap.cjs'; diff --git a/svelte-sitemap.cjs b/svelte-sitemap.cjs new file mode 100644 index 0000000..96a8d67 --- /dev/null +++ b/svelte-sitemap.cjs @@ -0,0 +1,4 @@ +module.exports = { + domain: 'https://www.example.com', + debug: true +}; diff --git a/tsconfig.json b/tsconfig.json index c533707..807c29b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,6 @@ "noImplicitAny": true, "noImplicitReturns": true }, - "include": ["src", "index.ts"], + "include": ["src", "index.ts", "svelte-sitemap.cjs"], "exclude": ["dist/**/*", "*/tests/**/*"] } diff --git a/yarn.lock b/yarn.lock index edad8ad..5257d84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,13 +9,20 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== dependencies: "@babel/highlight" "^7.16.7" +"@babel/code-frame@^7.12.13": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" @@ -339,6 +346,15 @@ "@babel/traverse" "^7.18.2" "@babel/types" "^7.18.2" +"@babel/highlight@^7.14.5": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" + integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/highlight@^7.16.7": version "7.16.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" @@ -357,11 +373,16 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": +"@babel/parser@^7.1.0", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== +"@babel/parser@^7.14.7", "@babel/parser@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + "@babel/parser@^7.18.0": version "7.18.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef"