Rollup
是一个JavaScript
模块打包器,可以将小块代码编译成大块复杂的代码,例如library
或应用程序import { rollup, watch } from 'rollup';
import inputOptions from './rollup.config.js'
; (async function () {
//打包阶段
const bundle = await rollup(inputOptions);
//生成阶段
await bundle.generate(inputOptions.output);
//写入阶段
await bundle.write(inputOptions.output);
/*
const watcher = watch(inputOptions);
watcher.on('event', event => {
console.log(event);
});
setTimeout(() => {
watcher.close();
}, 1000); */
//关闭阶段
await bundle.close();
})();
rollup.config.js
export default {
input: "./src/index.js",
output: {
dir: 'dist',
}
}
package.json
{
"scripts": {
"build": "rollup -c"
},
}
rollup-plugin-prefix
sourcemap
\0
。这会阻止其他插件尝试处理它async
钩子还可以返回解析为相同类型值的Promise
;否则,钩子将被标记为sync
first
如果有几个插件实现了这个钩子,钩子会按顺序运行,直到钩子返回一个非null
或未定义的值sequential
如果几个插件实现了这个钩子,那么它们都将按照指定的插件顺序运行。如果一个钩子是异步的,那么这种类型的后续钩子将等待当前钩子被解析parallel
如果多个插件实现了这个钩子,那么它们都将按照指定的插件顺序运行。如果一个钩子是异步的,那么这类后续钩子将并行运行,而不是等待当前钩子Build Hooks
在构建阶段运行,该阶段由rollup.rollup(inputOptions)
触发rollup
处理输入文件之前定位、提供和转换输入文件options
,最后一个钩子总是buildEnd
closeBundle
plugins\rollup-plugin-build.js
import fs from 'fs';
function build() {
return {
name: 'build',
async watchChange(id, change) {
console.log('watchChange', id, change);
},
async closeWatcher() {
console.log('closeWatcher');
},
async options(inputOptions) {
console.log('options');
//inputOptions.input = './src/main.js';
},
async buildStart(inputOptions) {
console.log('buildStart');
},
async resolveId(source, importer) {
if (source === 'virtual') {
console.log('resolveId', source);
//如果resolveId钩子有返回值了,那么就会跳过后面的查找逻辑,以此返回值作为最终的模块ID
return source;
}
},
//加载此模块ID对应的内容
async load(id) {
if (id === 'virtual') {
console.log('load', id);
return `export default "virtual"`;
}
},
async shouldTransformCachedModule({ id, code, ast }) {
console.log('shouldTransformCachedModule');
//不使用缓存,再次进行转换
return true;
},
async transform(code, id) {
console.log('transform');
},
async moduleParsed(moduleInfo) {
console.log('moduleParsed');
},
async resolveDynamicImport(specifier, importer) {
console.log('resolveDynamicImport', specifier, importer);
},
async buildEnd() {
console.log('buildEnd');
}
}
}
export default build;
rollup.config.js
+import build from './plugins/rollup-plugin-build.js';
export default {
input: "./src/index.js",
output: [{
dir: 'dist',
}],
plugins: [
+ build()
]
}
字段 | 值 | |
---|---|---|
Type | (options: InputOptions) => InputOptions | null |
Kind | async, sequential | |
Previous Hook | 这是构建阶段的第一个钩子 | |
Next Hook | buildStart |
rollup
的选项对象null
的话rollup不会替换任何内容options
,建议使用buildStart
钩子,因为在考虑了所有选项钩子的转换后,该钩子可以访问选项字段 | 值 |
---|---|
Type | (options: InputOptions) => void |
Kind | async, parallel |
Previous Hook | options |
Next Hook | resolveId并行解析每个入口点 |
rollup.rollup build
都要调用此钩子options
钩子的转换,还包含未设置选项的正确默认值build\plugin-buildStart.js
export default function buildStart() {
return {
name: 'buildStart',
buildStart(InputOptions) {
console.log('buildStart', InputOptions);
}
};
}
字段 | 值 | ||
---|---|---|---|
Type | (source, importer) => string | false | null |
Kind | async, first | ||
Previous Hook | buildStart (如果我们正在解析入口点),moduleParsed (如果我们正在解析导入),或者作为resolveDynamicImport 的后备方案。此外,这个钩子可以在构建阶段通过调用插件钩子触发。emitFile 发出一个入口点,或在任何时候通过调用此。resolve 可手动解析id |
||
Next Hook | 如果解析的id 尚未加载,则load ,否则buildEnd |
source
是导入语句中所写的导入对象,即来源就是 "../bar.js"
import { foo } from '../bar.js';
importer
是导入模块的完全解析id
importer
通常是undefinedthis.emitFile
生成的入口点。在这里,您可以提供一个importer
参数isEntry
选项将告诉您,我们是否正在解析用户定义的入口点、发出的块,或者是否为此提供了isEntry
参数。解析上下文函数polyfill
导入null
将遵循其他resolveId
函数,最终遵循默认的解析行false
信号,表示源应被视为外部模块
,不包括在bundle
中index.js
import virtual from 'virtual-module'
console.log(virtual);
build\plugin-polyfill.js
//我们在polyfill id前面加上\0,告诉其他插件不要尝试加载或转换它
const POLYFILL_ID = '\0polyfill';
const PROXY_SUFFIX = '?inject-polyfill-proxy';
export default function injectPolyfillPlugin() {
return {
name: 'inject-polyfill',
async resolveId(source, importer, options) {
if (source === POLYFILL_ID) {
//重要的是,对于polyfills,应始终考虑副作用
//否则,使用`treeshake.moduleSideEffects:false`可能会阻止包含polyfill
return { id: POLYFILL_ID, moduleSideEffects: true };
}
if (options.isEntry) {
//确定实际的入口是什么。我们需要skipSelf来避免无限循环。
const resolution = await this.resolve(source, importer, { skipSelf: true, ...options });
//如果它无法解决或是外部的,只需返回它,这样Rollup就可以显示错误
if (!resolution || resolution.external) return resolution;
//在代理的加载钩子中,我们需要知道入口是否有默认导出
//然而,在那里,我们不再有完整的“解析”对象,它可能包含来自其他插件的元数据,这些插件只在第一次加载时添加
//仅在第一次加载时添加。因此我们在这里触发加载。
const moduleInfo = await this.load(resolution);
//我们需要确保即使对于treeshake来说,原始入口点的副作用也得到了考虑。moduleSideEffects:false。
//moduleSideEffects是ModuleInfo上的一个可写属性
moduleInfo.moduleSideEffects = true;
//重要的是,新入口不能以\0开头,并且与原始入口具有相同的目录,以免扰乱相对外部导入的生成
//此外,保留名称并在末尾添加一个“?查询”可以确保preserveModules将为该条目生成原始条目名称
return `${resolution.id}${PROXY_SUFFIX}`;
}
return null;
},
load(id) {
if (id === POLYFILL_ID) {
// 替换为实际的polyfill import '@babel/polyfill'
return "console.log('polyfill');";
}
if (id.endsWith(PROXY_SUFFIX)) {
const entryId = id.slice(0, -PROXY_SUFFIX.length);
//我们知道ModuleInfo.hasDefaultExport是可靠的,因为我们在等待在resolveId中的this.load
// We know ModuleInfo.hasDefaultExport is reliable because we awaited this.load in resolveId
const { hasDefaultExport } = this.getModuleInfo(entryId);
let code =
`import ${JSON.stringify(POLYFILL_ID)};` + `export * from ${JSON.stringify(entryId)};`;
//命名空间重新导出不会重新导出默认值,因此我们需要在这里进行特殊处理
if (hasDefaultExport) {
code += `export { default } from ${JSON.stringify(entryId)};`;
}
return code;
}
return null;
}
};
}
字段 | 值 | |
---|---|---|
(id) => string | null | |
Kind | async, first | |
Previous Hook | 解析加载id的resolveId 或resolveDynamicImport 。此外,这个钩子可以在任何时候从插件钩子中通过调用this.load 来触发预加载与id对应的模块 |
|
Next Hook | transform 可在未使用缓存或没有使用相同代码的缓存副本时转换加载的文件,否则应使用TransformCachedModule |
null
会推迟到其他加载函数(最终是从文件系统加载的默认行为){code,AST,map}
对象。ast
必须是标准的ESTree ast
,每个节点都有开始和结束属性。如果转换不移动代码,可以通过将map设置为null来保留现有的sourcemaps。否则,您可能需要生成源映射。请参阅关于源代码转换的部分字段 | 值 |
---|---|
Type | (code, id) => string |
Kind | async, sequential |
Previous Hook | load 当前处理的文件的位置。如果使用了缓存,并且有该模块的缓存副本,那么如果插件为该钩子返回true,则应shouldTransformCachedModule |
Next Hook | moduleParsed 一旦文件被处理和解析,模块就会被解析 |
this.parse
出于某种原因,为了生成AST{code,AST,map}
对象start
和end
属性plugins\rollup-plugin-babel.js
import { createFilter } from 'rollup-pluginutils'
import babel from '@babel/core'
function plugin(pluginOptions = {}) {
const defaultExtensions = ['.js', '.jsx']
const { exclude, include, extensions = defaultExtensions } = pluginOptions;
const extensionRegExp = new RegExp(`(${extensions.join('|')})$`)
const userDefinedFilter = createFilter(include, exclude);
const filter = id => extensionRegExp.test(id) && userDefinedFilter(id);
return {
name: 'babel',
async transform(code, filename) {
if (!filter(filename)) return null;
let result = await babel.transformAsync(code);
return result
}
}
}
export default plugin
字段 | 值 |
---|---|
Type | ({id, code, ast, resoledSources, moduleSideEffects, syntheticNamedExports) => boolean |
Kind: async, first | |
Previous Hook | load 加载缓存文件以将其代码与缓存版本进行比较的位置 |
Next Hook | moduleParsed if no plugin returns true, otherwise transform . |
Rollup
缓存(例如,在监视模式下或通过JavaScript API显式使用),如果在加载钩子之后,加载的代码与缓存副本的代码相同,则Rollup将跳过模块的转换钩子npx rollup -c -w
shouldTransformCachedModule
transform
moduleParsed
shouldTransformCachedModule
moduleParsed
字段 | 值 |
---|---|
Type | (moduleInfo: ModuleInfo) => void |
Kind: async, parallel | |
Previous Hook | transform 转换当前处理的文件的位置 |
Next Hook | resolveId 和 resolveDynamicImport 并行解析所有发现的静态和动态导入(如果存在),否则buildEnd |
Rollup
完全解析时,就会调用这个钩子。看看this.getModuleInfo
了解传递给这个钩子的信息transform
钩子不同,这个钩子从不缓存,可以用来获取缓存模块和其他模块的信息,包括元属性的最终形状、代码和ast字段 | 值 |
---|---|
Type | (specifier, importer) => string |
Kind | async, first |
Previous Hook | moduleParsed 已为导入文件分配模块 |
Next Hook | load 如果钩子使用尚未加载的id ,如果动态导入包含字符串且钩子未解析,请加载resolveId ,否则为buildEnd |
false
表明导入应该保持原样,而不是传递给其他解析程序,从而使其成为外部的resolveId
钩子类似,还可以返回一个对象,将导入解析为不同的id,同时将其标记为外部index.js
import('./msg.js').then(res => console.log(res))
字段 | 值 |
---|---|
Type | (error) => void |
Kind | async, parallel |
Previous Hook | moduleParsed, resolveId or resolveDynamicImport. |
Next Hook | outputOptions 输出生成阶段的输出,因为这是构建阶段的最后一个挂钩 |
rollup
完成打包时调用,但在调用generate
或write
之前调用;你也可以返回一个Promise
outputOptions
,最后一个钩子要么generateBundle
是通过成功生成输出renderError
closeBundle
可以作为最后一个钩子调用,但用户有责任手动调用bundle.close()
以触发此钩子plugins\rollup-plugin-generation.js
function generation() {
return {
name: 'rollup-plugin-generation',
//这个钩子是同步的,不能加async
outputOptions(outputOptions) {
console.log('outputOptions');
},
renderStart() {
console.log('renderStart');
},
banner() {
console.log('banner');
},
footer() {
console.log('footer');
},
intro() {
console.log('intro');
},
outro() {
console.log('outro');
},
renderDynamicImport() {
console.log('renderDynamicImport');
},
augmentChunkHash() {
console.log('augmentChunkHash');
},
resolveFileUrl() {
console.log('resolveFileUrl');
},
resolveImportMeta() {
console.log('resolveImportMeta');
},
renderChunk() {
console.log('renderChunk');
},
generateBundle() {
console.log('generateBundle');
},
writeBundle() {
console.log('writeBundle');
},
renderError() {
console.log('renderError');
},
closeBundle() {
console.log('closeBundle');
}
}
}
export default generation;
rollup.config.js
import build from './plugins/rollup-plugin-build.js';
+import generation from './plugins/rollup-plugin-generation.js';
export default {
input: "./src/index.js",
output: [{
dir: 'dist',
}],
plugins: [
build(),
+ generation()
]
}
字段 | 值 |
---|---|
Type | (outputOptions) => null |
Kind | async, parallel |
Previous Hook | buildEnd 如果这是第一次生成输出,否则为generateBundle ,writeBundle 或renderError 取决于先前生成的输出。这是输出生成阶段的第一个钩子 |
Next Hook | outputOptions 输出生成阶段的输出,因为这是构建阶段的最后一个挂钩 |
bundle.generate()
的输出选项对象bundle.write()
null
并不能代替任何东西renderStart
钩子,因为在考虑renderStart
所有钩子的转换后,此钩子可以访问输出选项字段 | 值 |
---|---|
Type | (outputOptions, inputOptions) => void |
种类 | async, parallel |
上一个钩子 | outputOptions |
下一个钩子 | banner, footer, intro and outro 并行运行 |
bundle.generate()
或被bundle.write()
调用generateBundle
和renderError
挂钩bundle.generate()
或者bundle.write()
因为它考虑了所有outputOptions
挂钩的转换,并且还包含未设置选项的正确默认值。它还接收传递给的输入选项字段 | 值 | |
---|---|---|
Type | string | (() => string) |
Kind | async, parallel | |
Previous Hook | renderStart | |
Next Hook | 针对每个动态导入表达式 renderDynamicImport |
字段 | 值 | |
---|---|---|
Type | string | (() => string) |
Kind | async, parallel | |
Previous Hook | renderStart | |
Next Hook | 针对每个动态导入表达式 renderDynamicImport |
字段 | 值 | |
---|---|---|
Type | string | (() => string) |
Kind | async, parallel | |
Previous Hook | renderStart | |
Next Hook | 针对每个动态导入表达式 renderDynamicImport |
字段 | 值 | |
---|---|---|
Type | string | (() => string) |
Kind | async, parallel | |
Previous Hook | renderStart | |
Next Hook | 针对每个动态导入表达式 renderDynamicImport |
字段 | 值 |
---|---|
Type | ({format, moduleId, targetModuleId, customResolution}) => {left: string, right: string} |
Kind | async, parallel |
Previous Hook | banner , footer, intro, outro |
Next Hook | augmentChunkHash 对于每个在文件名中包含哈希的块 |
plugins\rollup-plugin-renderDynamicImport.js
export default function dynamicImportPolyfillPlugin() {
return {
name: 'dynamic-import-polyfill',
renderDynamicImport() {
return {
left: 'dynamicImportPolyfill(',
right: ', import.meta.url)'
};
}
};
}
dynamicImportPolyfill('./msg-ca034dda.js', import.meta.url).then(res => console.log(res.default));
function dynamicImportPolyfill(filename, url) {
return new Promise((resolve) => {
const script = document.createElement("script");
script.type = "module";
script.onload = () => {
resolve(window.mod);
};
const absURL = new URL(filename, url).href;
console.log(absURL);
const blob = new Blob([
`import * as mod from "${absURL}";`,
` window.mod = mod;`], { type: "text/javascript" });
script.src = URL.createObjectURL(blob);
document.head.appendChild(script);
});
}
字段 | 值 |
---|---|
Type | (chunkInfo: ChunkInfo) => string |
Kind | sync, sequential |
Previous Hook | renderDynamicImport针对每个动态导入表达式 |
Next Hook | resolveFileUrl 对于每次使用import.meta.ROLLUP_FILE_URL_referenceId 和resolveImportMeta 所有其他访问import.meta |
Rollup
输出块调用false
值不会修改散列hash.update
.chunkInfo
是generateBundle
不依赖文件名的属性的简化版本字段 | 值 |
---|---|
Type | ({chunkId, fileName, format, moduleId, referenceId, relativePath}) => string |
Kind | sync, first |
Previous Hook | augmentChunkHash 对于在文件名中包含哈希的每个块 |
Next Hook | renderChunk 对于每个块 |
this.emitFile
import.meta.ROLLUP_FILE_URL_referenceId
该代码应正确生成发出文件的绝对URL,而与输出格式和部署代码的主机系统无关src\index.js
import logger from 'logger'
console.log(logger);
plugins\rollup-plugin-resolveFileUrl.js
export default function resolveFileUrl() {
return {
name: 'resolveFileUrl',
resolveId(source) {
if (source === 'logger') {
return source;
}
},
load(importee) {
if (importee === 'logger') {
let referenceId = this.emitFile({ type: 'asset', source: 'console.log("logger")', fileName: "logger.js" });
return `export default import.meta.ROLLUP_FILE_URL_${referenceId}`;
}
},
resolveFileUrl({ chunkId, fileName, format, moduleId, referenceId, relativePath }) {//import.meta.url
return `new URL('${fileName}', document.baseURI).href`;
}
};
}
字段 | 值 |
---|---|
Type | (property, {chunkId, moduleId, format}) => string |
Kind | sync, first |
Previous Hook | augmentChunkHash 对于在文件名中包含哈希的每个块 |
Next Hook | renderChunk 对于每个块 |
import.meta
,import.meta.someProperty
特别是import.meta.url
import.meta
是一个对象,import.meta.url
包含当前模块的 URL字段 | 值 |
---|---|
Type | (code, chunk, options) => string |
Kind | async, sequential |
Previous Hook | resolveFileUrl 对于 . 的每次使用import.meta.ROLLUP_FILE_URL_referenceId 和resolveImportMeta 所有其他访问import.meta |
Next Hook | generateBundle |
rollup
输出块文件调用。返回null将不应用任何转换字段 | 值 |
---|---|
Type | (options, bundle, isWrite) => void |
Kind | async, sequential |
Previous Hook | renderChunk对于每个块 |
Next Hook | writeBundle 如果输出是通过生成的,否则这是输出生成阶段的最后一个钩子,如果生成另一个输出bundle.write() ,可能会再次跟随outputOptions |
bundle.generate()
之后调用bundle.write()
把文件写入之前调用writeBundle
挂钩writeBundle
提供正在写入或生成的文件的完整列表及其详细信息this.emitFile
插件上下文功能plugins\rollup-plugin-html.js
import dedent from 'dedent';
export default function html() {
return {
name: 'html',
generateBundle(options, bundle) {
let entryName;
for (let fileName in bundle) {
let assetOrChunkInfo = bundle[fileName];
//console.log(fileName, assetOrChunkInfo);
if (assetOrChunkInfo.isEntry) {
entryName = fileName;
}
}
this.emitFile({
type: 'asset',
fileName: 'index.html',
source: dedent`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>rollup</title>
</head>
<body>
<script src="${entryName}" type="module"></script>
</body>
</html>`
});
}
};
}
字段 | 值 |
---|---|
Type | (options,bundle) => void |
Kind | async, parallel |
Previous Hook | generateBundle |
Next Hook | 如果被调用,这是输出生成阶段的最后一个钩子,如果生成另一个输出,可能会再次跟随outputOptions |
bundle.write()
仅在写入所有文件后才调用generateBundle
钩子类似,bundle
提供正在写入的文件的完整列表及其详细信息字段 | 值 |
---|---|
Type | (error: Error) => void |
Kind | async, parallel |
Previous Hook | renderStart从到 的任何钩子renderChunk |
Next Hook | outputOptions 如果它被调用,这是输出生成阶段的最后一个钩子,如果生成另一个输出,可能会再次跟随 |
bundle.generate()
当 rollup 在或期间遇到错误时调用bundle.write()
generateBundle
钩子字段 | 值 | |
---|---|---|
Type | closeBundle: () => Promise |
void |
Kind | async, parallel | |
Previous Hook | buildEnd 如果有构建错误.否则何时bundle.close()被调用,在这种情况下,这将是最后一个被触发的钩子。 |
Rollup
的 CLI
将确保在每次运行后调用此钩子JavaScript API
的用户有责任在bundle.close()
他们完成生成包后手动调用type EmittedChunk = {
type: 'chunk';
id: string;
name?: string;
fileName?: string;
};
type EmittedAsset = {
type: 'asset';
name?: string;
fileName?: string;
source?: string | Uint8Array;
};
pnpm install rollup-pluginutils @rollup/plugin-babel @babel/core @babel/preset-env -D
plugins\rollup-plugin-babel.js
import { createFilter } from 'rollup-pluginutils'
import babel from '@babel/core'
function plugin(pluginOptions = {}) {
const defaultExtensions = ['.js', '.jsx']
const { exclude, include, extensions = defaultExtensions } = pluginOptions;
const extensionRegExp = new RegExp(
`(${extensions.join('|')})$`
)
const userDefinedFilter = createFilter(include, exclude);
const filter = id => extensionRegExp.test(id) && userDefinedFilter(id);
return {
name: 'babel',
async transform(code, filename) {
if (!filter(filename)) return null;
let result = await babel.transformAsync(code);
return result
}
}
}
export default plugin
rollup.config.js
+//import babel from '@rollup/plugin-babel'
+import babel from './plugins/rollup-plugin-babel'
export default {
input: "./src/index.js",
output: [{
dir: 'dist',
}],
plugins: [
+ babel()
]
}
pnpm install @rollup/plugin-commonjs --D
src\index.js
import catValue from './cat.js';
console.log(catValue);
src\cat.js
module.exports = 'catValue';
plugins\rollup-plugin-commonjs.js
import { createFilter } from 'rollup-pluginutils'
import MagicString from 'magic-string';
import { walk } from 'estree-walker';
import path from 'path';
export default function (pluginOptions = {}) {
const defaultExtensions = ['.js', '.jsx']
const { exclude, include, extensions = defaultExtensions } = pluginOptions;
const extensionRegExp = new RegExp(
`(${extensions.join('|')})$`
)
const userDefinedFilter = createFilter(include, exclude);
const filter = id => extensionRegExp.test(id) && userDefinedFilter(id);
return {
name: 'commonjs',
transform(code, id) {
if (!filter(id)) return null;
const result = transformAndCheckExports(this.parse, code, id)
return result;
}
}
}
function transformAndCheckExports(parse, code, id) {
const { isEsModule, ast } = analyzeTopLevelStatements(parse, code, id);
if (isEsModule) {
return null;
}
return transformCommonjs(code, id, ast)
}
function getKeypath(node) {
const parts = [];
while (node.type === 'MemberExpression') {
parts.unshift(node.property.name);
node = node.object;
}
if (node.type !== 'Identifier') return null;
const { name } = node;
parts.unshift(name);
return { name, keypath: parts.join('.') };
}
function analyzeTopLevelStatements(parse, code) {
const ast = parse(code);
let isEsModule = false;
for (const node of ast.body) {
switch (node.type) {
case 'ExportDefaultDeclaration':
isEsModule = true;
break;
case 'ExportNamedDeclaration':
isEsModule = true;
break;
case 'ImportDeclaration':
isEsModule = true;
break;
default:
}
}
return { isEsModule, ast };
}
function transformCommonjs(code, id, ast) {
const magicString = new MagicString(code);
const exportDeclarations = [];
let moduleExportsAssignment;
walk(ast, {
enter(node) {
switch (node.type) {
case 'AssignmentExpression':
if (node.left.type === 'MemberExpression') {
const flattened = getKeypath(node.left);
if (flattened.keypath === 'module.exports') {
moduleExportsAssignment = node;
}
}
break;
default:
break;
}
}
});
const { left } = moduleExportsAssignment;
const exportsName = path.basename(id, path.extname(id));
magicString.overwrite(left.start, left.end, exportsName);
magicString.prependRight(left.start, 'var ');
exportDeclarations.push(`export default ${exportsName};`);
const exportBlock = `\n\n${exportDeclarations.join('\n')}`;
magicString.trim().append(exportBlock);
return {
code: magicString.toString()
}
}
rollup.config.js
//import babel from '@rollup/plugin-babel'
//import babel from './plugins/rollup-plugin-babel.js'
//import commonjs from '@rollup/plugin-commonjs'
+import commonjs from './plugins/rollup-plugin-commonjs'
export default {
input: "./src/index.js",
output: {
dir: 'dist'
},
plugins: [
//babel(),
+ commonjs()
]
}
pnpm install @rollup/plugin-node-resolve check-is-array -D
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
isarray (imported by src/index.js)
src\index.js
import isArray from 'check-is-array';
console.log(isArray);
plugins\rollup-plugin-node-resolve.js
import path from 'path';
import Module from 'module';
function resolve() {
return {
name: 'resolve',
//因为我们要改造根据模块的名称查找模所路径的逻辑
async resolveId(importee, importer) {
//如果是相对路径,则走默认逻辑
if (importee[0] === '.' || path.isAbsolute(importee)) {
return null;
}
let location = Module.createRequire(path.dirname(importer)).resolve(importee);
console.log(location);
return location;
}
}
}
export default resolve;
rollup.config.js
//import build from './plugins/rollup-plugin-build.js';
//import polyfill from './plugins/rollup-plugin-inject-polyfill.js';
//import babel from './plugins/rollup-plugin-babel.js';
//import generation from './plugins/rollup-plugin-generation.js';
//import importPolyFill from './plugins/rollup-plugin-import-polyfill.js';
//import commonjs from '@rollup/plugin-commonjs';
//import commonjs from './plugins/rollup-plugin-commonjs';
//import resolve from '@rollup/plugin-node-resolve';
import resolve from './plugins/rollup-plugin-node-resolve.js';
//import alias from '@rollup/plugin-alias';
import alias from './plugins/rollup-plugin-alias.js';
export default {
input: './src/index.js',
//watch: true,
output: {
//file: 'dist/main.js',
dir: 'dist'
},
plugins: [
resolve(),
alias({
entries: [
{ find: './xx.js', replacement: 'check-is-array' }
]
}),
],
watch: {
clearScreen: false
}
}
plugins\rollup-plugin-alias.js
function matches(pattern, importee) {
if (pattern instanceof RegExp) {
return pattern.test(importee);
}
if (importee.length < pattern.length) {
return false;
}
if (importee === pattern) {
return true;
}
return importee.startsWith(pattern + '/');
}
function alias(options = {}) {
const { entries } = options;
if (entries.length === 0) {
return {
name: 'alias',
resolveId: () => null
};
}
return {
name: 'alias',
resolveId(importee, importer) {
if (!importer) {
return null;
}
const matchedEntry = entries.find((entry) => matches(entry.find, importee));
if (!matchedEntry) {
return null;
}
const updatedId = importee.replace(matchedEntry.find, matchedEntry.replacement);
//调用this.resolve意味着重新解析
return this.resolve(updatedId, importer, Object.assign({ skipSelf: true }))
.then((resolved) => resolved || { id: updatedId });
}
};
}
export default alias;