diff --git a/README.md b/README.md index 252ec45..1eddcd1 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ meta: { ```js { + crossorigin?: 'anonymous' | 'use-credentials' file: string type?: undefined | 'css' | 'js' pos: 'before' | 'after' @@ -132,7 +133,8 @@ meta: { An array of additional files that will be injected to the output HTML document. Only CSS and JS files are accepted. The optional `type` property points which type of file is injected. If type is `undefined` then it is detected based on the file extension. The `pos` property points when the file is inserted: -before processing the budnled files or after. +before processing the bundled files or after. The optional `crossorigin` property points whether to place +the CORS attribute to the generated tag. ##### Example diff --git a/example/rollup.config.js b/example/rollup.config.js index 7f166bf..d0b6337 100644 --- a/example/rollup.config.js +++ b/example/rollup.config.js @@ -22,6 +22,7 @@ export default { externals: [{ file: 'https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css', pos: 'before', + crossorigin: 'use-credentials', }], preload: ['lib'], minify: { diff --git a/src/index.ts b/src/index.ts index 6704fa1..3b33ddb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,19 +30,23 @@ const enum InjectType { js = 'js', } -const enum ExternalPosition { +enum ExternalPosition { before = 'before', after = 'after', } +enum Crossorigin { + anonymous = 'anonymous', + usecredentials = 'use-credentials', +} + interface IExternal { + crossorigin?: Crossorigin file: string type?: InjectType pos: ExternalPosition } -type ExtrenalsProcessor = (pos: ExternalPosition) => void - interface IPluginOptions { template: string file?: string @@ -111,6 +115,55 @@ const formatSupportsModules = (f?: ModuleFormat) => ( || f === 'module' ) +const checkEnum = (enumobj: T, val?: string) => ( + !val || Object.values(enumobj).includes(val) +) + +const injectCSSandJSFactory = ( + head: HTMLElement, + body: HTMLElement, + modules?: boolean, +) => { + const typeModule = modules ? 'type="module" ' : '' + + return ( + fileName: string, + type: InjectType | string, + pos?: Inject, + crossorigin?: Crossorigin, + ) => { + const cors = crossorigin ? `crossorigin="${crossorigin}" ` : '' + if (type === InjectType.css) { + const parent = pos === Inject.body ? body : head + addNewLine(parent) + parent.appendChild(new HTMLElement('link', {}, `rel="stylesheet" ${cors}href="/${fileName}"`)) + } else { + const parent = pos === Inject.head ? head : body + addNewLine(parent) + parent.appendChild(new HTMLElement('script', {}, `${typeModule}${cors}src="/${fileName}"`)) + } + } +} + +type ExtrenalsProcessor = (pos: ExternalPosition) => void + +const extrenalsProcessorFactory = ( + injectCSSandJS: ReturnType, + externals?: IExternal[], +): ExtrenalsProcessor => { + if (!externals) { + // tslint:disable-next-line: no-empty + return (_pos) => {} + } + return (processPos) => { + for (const {pos, file, type, crossorigin} of externals) { + if (pos === processPos) { + injectCSSandJS(file, type || path.extname(file).slice(1), undefined, crossorigin) + } + } + } +} + export default ({ template, file, @@ -150,10 +203,13 @@ export default ({ } if (externals) { - for (const {pos} of externals) { - if (pos !== ExternalPosition.before && pos !== ExternalPosition.after) { + for (const {pos, crossorigin} of externals) { + if (!checkEnum(ExternalPosition, pos)) { this.error('Invalid position for the extrenal: ' + pos) } + if (!checkEnum(Crossorigin, crossorigin)) { + this.error('Invalid crossorigin argument for the extrenal: ' + crossorigin) + } } } @@ -248,35 +304,8 @@ consider to use the esm format or switch off the option`) } } - const injectCSSandJS = (fileName: string, type: string, pos: Inject | undefined = undefined) => { - const cssParent = pos !== Inject.body ? head : body - const jsParent = pos !== Inject.head ? body : head - switch (type) { - case InjectType.css: - addNewLine(cssParent) - cssParent.appendChild(new HTMLElement('link', {}, `rel="stylesheet" href="/${fileName}"`)) - break - case InjectType.js: - addNewLine(jsParent) - const typeModule = modules ? 'type="module" ' : '' - jsParent.appendChild(new HTMLElement('script', {}, `${typeModule}src="/${fileName}"`)) - break - default: - break - } - } - - const processExternals: ExtrenalsProcessor = externals ? - (pos) => { - for (const external of externals) { - if (external.pos === pos) { - injectCSSandJS(external.file, external.type || path.extname(external.file).slice(1)) - } - } - } - : -// tslint:disable-next-line: no-empty - (_pos) => {} + const injectCSSandJS = injectCSSandJSFactory(head, body, modules) + const processExternals = extrenalsProcessorFactory(injectCSSandJS, externals) // Inject externals before processExternals(ExternalPosition.before)