diff --git a/src/index.js b/src/index.js index 4706359..15fa124 100644 --- a/src/index.js +++ b/src/index.js @@ -19,6 +19,7 @@ const defaultOptions = require('./lib/default-options') const determineAsValue = require('./lib/determine-as-value') const doesChunkBelongToHTML = require('./lib/does-chunk-belong-to-html') const extractChunks = require('./lib/extract-chunks') +const joinPaths = require('./lib/join-paths') class PreloadPlugin { constructor (options) { @@ -76,7 +77,7 @@ class PreloadPlugin { ? webpackPublicPath : '' : webpackPublicPath || '' for (const file of sortedFilteredFiles) { - const href = `${publicPath}${file}` + const href = joinPaths(publicPath, file) const attributes = { href, diff --git a/src/lib/join-paths.js b/src/lib/join-paths.js new file mode 100644 index 0000000..3a1e538 --- /dev/null +++ b/src/lib/join-paths.js @@ -0,0 +1,17 @@ + +function joinPaths (...segments) { + let joined = segments + .map((segment) => segment.replace(/^\/|\/$/g, '')) + .filter(Boolean) + .join('/') + + const first = segments[0] + const last = segments[segments.length - 1] + + if (first[0] === '/') joined = `/${joined}` + if (last[last.length - 1] === '/') joined = `${joined}/` + + return joined +} + +module.exports = joinPaths diff --git a/test/spec.js b/test/spec.js index 685b631..9a7c371 100644 --- a/test/spec.js +++ b/test/spec.js @@ -133,6 +133,40 @@ module.exports = ({ }) compiler.outputFileSystem = fs }) + + it('should gracefully handle missing publicPath separators', function (done) { + const fs = new MemoryFileSystem() + const compiler = webpack({ + entry: { + js: path.join(__dirname, 'fixtures', 'file.js') + }, + output: { + path: OUTPUT_DIR, + filename: 'bundle.js', + chunkFilename: 'chunk.[chunkhash].js', + publicPath: '/a' + }, + plugins: [ + new HtmlWebpackPlugin(), + new PreloadPlugin() + ] + }, function (err, result) { + expect(err).toBeFalsy(err) + expect(result.compilation.errors.length).toBe(0, + result.compilation.errors.join('\n=========\n')) + + const html = fs.readFileSync(path.join(OUTPUT_DIR, 'index.html'), 'utf-8') + const dom = new JSDOM(html) + + const links = dom.window.document.head.querySelectorAll('link') + expect(links.length).toBe(1) + expect(links[0].getAttribute('rel')).toBe('preload') + expect(links[0].getAttribute('href')).toMatch(new RegExp('^/a/chunk\\.')) + + done() + }) + compiler.outputFileSystem = fs + }) }) describe(`${descriptionPrefix} When passed non-async chunks, it`, function () {