async compile (context) {
        let generator = context.generator;
        context.plugins.start();

        let bundle = /** @type {RollupOutputFile[]} */ ([]);
        let bundleError = /** @type {Error} */ (undefined);
        let bundleStartTime = Date.now();
        let bundleEmittedChunks = /** @type {NollupInternalEmittedChunk[]} */ ([]);
        let bundleEmittedAssets = /** @type {NollupInternalEmittedAsset[]} */ ([]);
        let bundleModuleIds = new Set();
        let bundleMetaProperties = {};
        let bundleReferenceIdMap = /** @type {Object<string, RollupOutputChunk| RollupOutputAsset>} */ ({}); 
        let bundleOutputTypes = /** @type {Object<String, string>} */ ({});
        let bundleDynamicImports = /** @type {Object<string, string[]>} */ ({});
        let bundleCirculars = [];
        let bundleExternalImports = /** @type {Object<string, NollupInternalModuleImport[]>} */ ({});

        let invalidated = Object.keys(context.files).filter(filePath => context.files[filePath].invalidate);

        let addBundleEmittedChunks = function (dynamicImports, emittedChunks, modules) {
            
            dynamicImports.forEach(id => {
                // if the current chunk already includes the dynamic import content, then don't create a new chunk
                if (modules[id]) {
                    return;
                }

                let found = bundleEmittedChunks.find(o => o.id === id);
                if (!found) {
                    bundleEmittedChunks.push({
                        id: id,
                        name: getNameFromFileName(id),
                        isDynamicEntry: true,
                        isEntry: false
                    });
                }
            });

            Object.entries(emittedChunks).forEach(([referenceId, chunk]) => {
                let found = bundleEmittedChunks.find(o => o.id === chunk.id);
                let output = {
                    id: chunk.id,
                    name: chunk.name,
                    isDynamicEntry: false,
                    isEntry: true,
                    fileName: chunk.fileName,
                    referenceId: referenceId
                };
                
                if (!found) {
                    bundleEmittedChunks.push(output);
                } else {
                    found.referenceId = referenceId;
                }
            });
        };

        context.currentBundle = bundle;
        context.currentBundleModuleIds = bundleModuleIds;
        context.currentBundleReferenceIdMap = bundleReferenceIdMap;
        context.currentEmittedAssets = bundleEmittedAssets;

        try {
            context.currentPhase = 'pre-build';

            await context.plugins.hooks.buildStart(context.config);

            context.currentPhase = 'build';

            let inputs = await context.input();

            for (let i = 0; i < inputs.length; i++) {
                let { name, file } = inputs[i];                
                let emitted = await compileInputTarget(context, file, bundleModuleIds, generator, bundleEmittedAssets, true);

                bundle.push({
                    code: '',
                    name: name,
                    isEntry: true,
                    isDynamicEntry: false,
                    type: 'chunk',
                    map: null,
                    modules: emitted.modules,
                    fileName: '',
                    imports: emitted.externalImports.map(e => e.source),
                    importedBindings: emitted.externalImports.reduce((acc, val) => {
                        acc[val.source] = val.specifiers.map(s => s.imported);
                        return acc;
                    }, {}),
                    dynamicImports: [],
                    exports: context.files[file].exports.map(e => e.exported),
                    facadeModuleId: file,
                    implicitlyLoadedBefore: [],
                    referencedFiles: [],
                    isImplicitEntry: false
                }); 

                addBundleEmittedChunks(emitted.dynamicImports, emitted.chunks, emitted.modules);
                bundleMetaProperties[file] = emitted.metaProperties;
                bundleOutputTypes[file] = 'entry';
                bundleDynamicImports[file] = emitted.dynamicImports;
                bundleCirculars = bundleCirculars.concat(emitted.circulars);
                bundleExternalImports[file] = emitted.externalImports;
            }

            for (let i = 0; i < bundleEmittedChunks.length; i++) {
                let chunk = bundleEmittedChunks[i];
                let emitted = await compileInputTarget(context, chunk.id, bundleModuleIds, generator, bundleEmittedAssets, chunk.isEntry);

                let bundleEntry = {
                    code: '',
                    name: chunk.name,
                    isEntry: chunk.isEntry,
                    isDynamicEntry: chunk.isDynamicEntry,
                    type: /** @type {'chunk'} */ ('chunk'),
                    map: null,
                    modules: emitted.modules,
                    fileName: chunk.fileName,
                    facadeModuleId: chunk.id,
                    imports: emitted.externalImports.map(e => e.source),
                    importedBindings: emitted.externalImports.reduce((acc, val) => {
                        acc[val.source] = val.specifiers;
                        return acc;
                    }, {}),
                    dynamicImports: [],
                    exports: context.files[chunk.id].exports.map(e => e.exported),
                    implicitlyLoadedBefore: [], 
                    referencedFiles: [], 
                    isImplicitEntry: false
                };

                addBundleEmittedChunks(emitted.dynamicImports, emitted.chunks, emitted.modules);
                bundleMetaProperties[chunk.id] = emitted.metaProperties;
                bundleOutputTypes[chunk.id] = 'chunk';
                bundleDynamicImports[chunk.id] = emitted.dynamicImports;

                bundleReferenceIdMap[chunk.referenceId] = bundleEntry;
                bundleCirculars = bundleCirculars.concat(emitted.circulars);
                bundleExternalImports[chunk.id] = emitted.externalImports;
                bundle.push(bundleEntry);
            }
        } catch (e) {
            bundleError = e;
            throw e;
        } finally {
            context.currentPhase = 'post-build';
            await context.plugins.hooks.buildEnd(bundleError);
        }

        if (bundleCirculars.length > 0) {
            let show = bundleCirculars.slice(0, 3);
            let hide = bundleCirculars.slice(3);

            show = show.map(t => t.map(t => t.replace(process.cwd(), '')).join(' -> '));

            console.warn([
                yellow('(!) Circular dependencies'),
                ...show,
                hide.length > 0? `...and ${hide.length} more` : '',
                yellow('Code may not run correctly. See https://github.com/PepsRyuu/nollup/blob/master/docs/circular.md')
            ].join('\n'));
        }

        applyOutputFileNames(context.config.output, bundle, bundleOutputTypes);

        context.currentPhase = 'generate';

        bundleEmittedAssets.forEach(asset => {
            emitAssetToBundle(context.config.output, bundle, asset, bundleReferenceIdMap);
        });

        let modules = /** @type {Object<String, NollupOutputModule>} */(null);

        try {
            await context.plugins.hooks.renderStart(context.config.output, context.config);

            // clone files and their code
            modules = Object.entries(context.files).reduce((acc, val) => {
                let [ id, file ] = val;
                acc[id] = {
                    index: file.index,
                    code: generator.onGenerateModulePreChunk(file, bundle, context.files),
                };
                return acc;
            }, {});

            // Rendering hooks
            let [ banner, intro, outro, footer ] = await Promise.all([
                context.plugins.hooks.banner(),
                context.plugins.hooks.intro(),
                context.plugins.hooks.outro(),
                context.plugins.hooks.footer()
            ]);

            for (let i = 0; i < bundle.length; i++) {
                let bundleEntry = /** @type {RollupOutputChunk} */ (bundle[i]);
                if (bundleEntry.type === 'chunk') {
                    Object.entries(bundleMetaProperties[bundleEntry.facadeModuleId]).forEach(([moduleId, metaNames]) => {
                        metaNames.forEach(metaName => {
                            let resolved = resolveImportMetaProperty(context.plugins, moduleId, metaName, bundleEntry, bundleReferenceIdMap);
                            modules[moduleId].code = modules[moduleId].code.replace(
                                metaName === null? new RegExp('import\\.meta') : new RegExp('import\\.meta\\.' + metaName, 'g'),
                                resolved
                            );
                        });
                    });
                    
                    bundleEntry.code =
                         banner + '\n' +
                         intro + '\n' + 
                         generator.onGenerateChunk(modules, bundleEntry, context.config.output, context.config, bundleExternalImports[bundleEntry.facadeModuleId]) + '\n' + 
                         outro + '\n' + 
                         footer;

                    await context.plugins.hooks.renderChunk(bundleEntry.code, bundleEntry, context.config.output);
                }   
            }
        } catch (e) {
            await context.plugins.hooks.renderError(e);
            throw e;
        }
        
        await context.plugins.hooks.generateBundle(context.config.output, bundle);

        let removedIds = [...context.previousBundleModuleIds].filter(i => !bundleModuleIds.has(i));
        let addedIds = [...bundleModuleIds].filter(i => !context.previousBundleModuleIds.has(i));

        let changedIds = new Set(addedIds.concat(invalidated));
        context.previousBundleModuleIds = bundleModuleIds;

        let changes = removedIds.map(f => ({
            id: context.files[f].index,
            code: '',
            removed: true
        })).concat([...changedIds].map(f => ({
            id: context.files[f].index,
            code: generator.onGenerateModuleChange(modules[f]),
            removed: false
        })));

        return {
            stats: { time: Date.now() - bundleStartTime },
            changes: changes,
            output: bundle
        }
    }
@param {NollupContext} context 
@return {Promise<NollupCompileOutput>}