diff --git a/index.js b/index.js index 5d1ce7c..b277211 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ -const generator = require('./generator'); +const generator = require('./src/generator'); const path = require('path'); +const emitter = require('./src/emitter'); module.exports = (nextConfig) => ({ ...nextConfig, @@ -10,7 +11,6 @@ module.exports = (nextConfig) => ({ config: { sitemap = {} } } = options; - if (isServer) { console.log('[Sitemap Generator]: Generating Sitemap'); @@ -18,9 +18,17 @@ module.exports = (nextConfig) => ({ sitemap.publicPath = path.join(options.dir, 'public'); } - generator(sitemap); + sitemap.emitter = emitter.init({ + fileName: sitemap.fileName, + }) + + let sitemapData = generator(sitemap); - return config; + try { + sitemap.emitter.emit(sitemapData)(sitemap.publicPath); + } catch (error) { + console.error("[Sitemap Generator] Unable to write sitemap to storage. Build will continue") + } } if (typeof nextConfig.webpack === 'function') { diff --git a/package.json b/package.json index cebd1a8..9fc7a65 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "keywords": [ "javascript", "nextjs", + "nuxtjs", "prismic.io", "sitemap", "sitemap generator" @@ -13,6 +14,11 @@ "url": "https://github.com/reecem/prismic-sitemap" }, "main": "index.js", + "exports": { + ".": "./index.js", + "./next": "./src/next", + "./nuxt": "./src/nuxt" + }, "dependencies": {}, "devDependencies": { "cross-spawn": "^7.0.3", diff --git a/src/emitter.js b/src/emitter.js new file mode 100644 index 0000000..07e9ab3 --- /dev/null +++ b/src/emitter.js @@ -0,0 +1,65 @@ +const path = require("path"); +const fs = require("fs"); + +let emitter = { + data: Buffer.from('Empty Sitemap', 'utf-8'), + fileName: 'sitemap.xml', + + init({ + fileName, emitter = 'file', + }) { + this.fileName = fileName; + this.emitter = emitter; + return this; + }, + + fileWriter(publicPath) { + let basePath = resolvePublicPath(publicPath); + + if (!fs.existsSync(basePath)) { + fs.mkdirSync(basePath, { recursive: true }); + } + + return fs.writeFileSync( + path.join(basePath, this.fileName), + this.data, + "utf-8" + ); + }, + + webpackEmitter(compilation, cb) { + // This will generate `.nuxt/dist/filename.ext' with contents of source variable. + + compilation.assets[this.fileName] = { + source: () => this.data, + size: () => this.data.length + } + + cb() + }, + + emit(data) { + this.data = data; + + switch (this.emitter) { + case 'file': + return this.fileWriter.bind(this) + case 'nuxt': + return this.webpackEmitter.bind(this) + + default: + console.error(`Emitter [${this.emitter}] is not supported`) + return null; + } + } +} + +function resolvePublicPath(dir) { + if (dir === 'public') { + dir = path.join(__dirname, dir); + } + + return dir; +} + +module.exports = emitter; diff --git a/generator.js b/src/generator.js similarity index 73% rename from generator.js rename to src/generator.js index f92f7d5..5ba9572 100644 --- a/generator.js +++ b/src/generator.js @@ -1,5 +1,3 @@ -const path = require("path"); -const fs = require("fs"); const Prismic = require("prismic-javascript"); const { SitemapStream, streamToPromise } = require('sitemap'); @@ -21,8 +19,6 @@ const generator = async (sitemap) => { hostname = '', optionsMapPerDocumentType = {}, documentTypes = [], - fileName = 'sitemap.xml', - publicPath = 'public', sitemapConfig } = sitemap; @@ -56,25 +52,7 @@ const generator = async (sitemap) => { sitemapStream.end(); - const sitemapData = await streamToPromise(sitemapStream); - - let basePath = resolvePublicPath(publicPath) - - if (!fs.existsSync(path.join(basePath))) { - fs.mkdirSync(path.join(basePath), { recursive: true }); - } - - fs.writeFileSync(path.join(basePath, fileName), sitemapData, "utf-8"); - - return sitemapData; -} - -function resolvePublicPath(dir) { - if (dir === 'public') { - dir = path.join(__dirname, dir); - } - - return dir; + return await streamToPromise(sitemapStream); } module.exports = generator; diff --git a/src/nuxt/index.js b/src/nuxt/index.js new file mode 100644 index 0000000..f99b67d --- /dev/null +++ b/src/nuxt/index.js @@ -0,0 +1,34 @@ +import generator from '../generator' +import emitter from '../emitter' + +/** + * The main Nuxt module for generating the site map + * + * @author ReeceM + * @since 0.2.0 + * @param {*} moduleOptions + */ + +export default async function PrismicSitemap(moduleOptions) { + const options = Object.assign({}, this.options.sitemap, moduleOptions) + + this.nuxt.hook('ready', async nuxt => { + console.log('Nuxt is ready') + }) + + emitter.init({ + fileName: options.fileName, + emitter: 'nuxt', + }); + + let sitemapData = await generator(options); + + this.options.build.plugins.push({ + apply(compiler) { + compiler.plugin('emit', emitter.emit(sitemapData)) + } + }) +} + +// REQUIRED if publishing the module as npm package +module.exports.meta = require('../../package.json') diff --git a/tests/emitter.test.js b/tests/emitter.test.js new file mode 100644 index 0000000..76ce84b --- /dev/null +++ b/tests/emitter.test.js @@ -0,0 +1,58 @@ +/** + * Test File for the generator + */ +let fs = require('fs'); +let path = require('path'); + +jest.mock('fs'); +let generator = require('../src/generator'); +let emitter = require('../src/emitter'); + +let _emitter = emitter.init({ + fileName: 'sitemap.xml', +}) +let sitemapData = null; + +const sitemapConfig = { + linkResolver: doc => { + return doc.type == 'post' + ? `blog/${doc.uid}` + : `page/${doc.uid}`; + }, + apiEndpoint: process.env.TEST_REPOSITORY, + hostname: 'https://example.com', + documentTypes: ['post', 'page'], + optionsMapPerDocumentType: { + post: { changefreq: "weekly", priority: 0.8 }, + }, +}; + +describe('tests for generator.js', () => { + beforeAll(async () => { + // clear any previous calls + jest.restoreAllMocks(); + sitemapData = await generator(sitemapConfig); + _emitter.emit(sitemapData)(path.join(__dirname, "public")); + }); + + it('should check if exists', async () => { + + expect(jest.spyOn(fs, "existsSync")) + .toHaveBeenCalledWith(path.join(__dirname, "public")); + }); + + it('should have called 1 time', () => { + + expect(jest.spyOn(fs, 'writeFileSync')) + .toHaveBeenCalledTimes(1); + }); + + it('file write should have been called with ...', () => { + + expect(jest.spyOn(fs, 'writeFileSync')).toHaveBeenCalledWith( + path.join(__dirname, "public/sitemap.xml"), + require('./buffer-example'), + "utf-8" + ); + }); +}); diff --git a/tests/generator.test.js b/tests/generator.test.js index 3437881..29a9584 100644 --- a/tests/generator.test.js +++ b/tests/generator.test.js @@ -5,7 +5,7 @@ let fs = require('fs'); let path = require('path'); jest.mock('fs'); -let generator = require('../generator'); +let generator = require('../src/generator'); const sitemapConfig = { linkResolver: doc => { @@ -29,26 +29,33 @@ describe('tests for generator.js', () => { await generator(sitemapConfig); }); - it('should check if exists', async () => { + it('should return a sitemap with valid data', async () => { + let sitemapData = await generator(sitemapConfig); - expect(jest.spyOn(fs, "existsSync")) - .toHaveBeenCalledWith(path.join(__dirname, "../public")); - }); + expect(sitemapData) + .toEqual(require('./buffer-example')) + }) - it('should have called 1 time', () => { + // it('should check if exists', async () => { - expect(jest.spyOn(fs, 'writeFileSync')) - .toHaveBeenCalledTimes(1); - }); + // expect(jest.spyOn(fs, "existsSync")) + // .toHaveBeenCalledWith(path.join(__dirname, "../public")); + // }); - it('file write should have been called with ...', () => { + // it('should have called 1 time', () => { - expect(jest.spyOn(fs, 'writeFileSync')).toHaveBeenCalledWith( - path.join(__dirname, "../public/sitemap.xml"), - require('./buffer-example'), - "utf-8" - ); - }); + // expect(jest.spyOn(fs, 'writeFileSync')) + // .toHaveBeenCalledTimes(1); + // }); + + // it('file write should have been called with ...', () => { + + // expect(jest.spyOn(fs, 'writeFileSync')).toHaveBeenCalledWith( + // path.join(__dirname, "../public/sitemap.xml"), + // require('./buffer-example'), + // "utf-8" + // ); + // }); }); describe('generator errors', () => {