Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: produce single bundle for runtime with multiple entrypoints #8504

Merged
merged 12 commits into from
Apr 18, 2023
194 changes: 86 additions & 108 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,136 +14,113 @@ const is_publish = !!process.env.PUBLISH;

const ts_plugin = is_publish
? typescript({
typescript: require('typescript')
})
typescript: require('typescript'),
})
: sucrase({
transforms: ['typescript']
});
transforms: ['typescript'],
});

// The following external and path logic is necessary so that the bundled runtime pieces and the index file
// reference each other correctly instead of bundling their references to each other
fs.writeFileSync(
`./compiler.d.ts`,
`export { compile, parse, preprocess, walk, VERSION } from './types/compiler/index.js';`
);

/**
* Ensures that relative imports inside `src/runtime` like `./internal` and `../store` are externalized correctly
*/
const external = (id, parent_id) => {
const parent_segments = parent_id.replace(/\\/g, '/').split('/');
// TODO needs to be adjusted when we move to JS modules
if (parent_segments[parent_segments.length - 3] === 'runtime') {
return /\.\.\/\w+$/.test(id);
} else {
return id === './internal' && parent_segments[parent_segments.length - 2] === 'runtime';
}
}

/**
* Transforms externalized import paths like `../store` into correct relative imports with correct index file extension import
*/
const replace_relative_svelte_imports = (id, ending) => {
id = id.replace(/\\/g, '/');
// TODO needs to be adjusted when we move to JS modules
return /src\/runtime\/\w+$/.test(id) && `../${id.split('/').pop()}/${ending}`;
}
const runtime_entrypoints = Object.fromEntries(
fs
.readdirSync('src/runtime', { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => [dirent.name, `src/runtime/${dirent.name}/index.ts`])
);

/**
* Transforms externalized `./internal` import path into correct relative import with correct index file extension import
* @type {import("rollup").RollupOptions[]}
*/
const replace_relative_internal_import = (id, ending) => {
id = id.replace(/\\/g, '/');
// TODO needs to be adjusted when we move to JS modules
return id.endsWith('src/runtime/internal') && `./internal/${ending}`;
}

fs.writeFileSync(`./compiler.d.ts`, `export { compile, parse, preprocess, walk, VERSION } from './types/compiler/index';`);

export default [
/* runtime */
{
input: `src/runtime/index.ts`,
output: [
{
file: `index.mjs`,
format: 'esm',
paths: id => replace_relative_internal_import(id, 'index.mjs')
},
{
file: `index.js`,
format: 'cjs',
paths: id => replace_relative_internal_import(id, 'index.js')
}
],
external,
plugins: [ts_plugin]
},
input: {
...runtime_entrypoints,
index: 'src/runtime/index.ts',
ssr: 'src/runtime/ssr.ts'
},
output: ['es', 'cjs'].map(
/** @returns {import('rollup').OutputOptions} */
(format) => {
const ext = format === 'es' ? 'mjs' : 'js';
return {
entryFileNames: (entry) => {
if (entry.isEntry) {
if (entry.name === 'index') return `index.${ext}`;
else if (entry.name === 'ssr') return `ssr.${ext}`;

{
input: `src/runtime/ssr.ts`,
output: [
{
file: `ssr.mjs`,
format: 'esm',
paths: id => replace_relative_internal_import(id, 'index.mjs')
},
{
file: `ssr.js`,
format: 'cjs',
paths: id => replace_relative_internal_import(id, 'index.js')
return `${entry.name}/index.${ext}`;
}
},
chunkFileNames: `internal/[name]-[hash].${ext}`,
format,
minifyInternalExports: false,
dir: '.',
};
}
],
external,
plugins: [ts_plugin]
},

...fs.readdirSync('src/runtime')
.filter(dir => fs.statSync(`src/runtime/${dir}`).isDirectory())
.map(dir => ({
input: `src/runtime/${dir}/index.ts`,
output: [
{
file: `${dir}/index.mjs`,
format: 'esm',
paths: id => replace_relative_svelte_imports(id, 'index.mjs')
),
plugins: [
replace({
preventAssignment: true,
values: {
__VERSION__: pkg.version,
},
{
file: `${dir}/index.js`,
format: 'cjs',
paths: id => replace_relative_svelte_imports(id, 'index.js')
}
],
external,
plugins: [
replace({
__VERSION__: pkg.version
}),
ts_plugin,
{
writeBundle(_options, bundle) {
}),
ts_plugin,
{
writeBundle(options, bundle) {
if (options.format !== 'es') return;

for (const entry of Object.values(bundle)) {
const dir = entry.name;
if (!entry.isEntry || !runtime_entrypoints[dir]) continue;

if (dir === 'internal') {
const mod = bundle['index.mjs'];
const mod = bundle[`internal/index.mjs`];
if (mod) {
fs.writeFileSync('src/compiler/compile/internal_exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
fs.writeFileSync(
'src/compiler/compile/internal_exports.ts',
`// This file is automatically generated\n` +
`export default new Set(${JSON.stringify(mod.exports)});`
);
}
}

fs.writeFileSync(`${dir}/package.json`, JSON.stringify({
main: './index',
module: './index.mjs',
types: './index.d.ts'
}, null, ' '));
fs.writeFileSync(
`${dir}/package.json`,
JSON.stringify(
{
main: './index.js',
module: './index.mjs',
types: './index.d.ts',
},
null,
' '
)
);

fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index';`);
fs.writeFileSync(
`${dir}/index.d.ts`,
`export * from '../types/runtime/${dir}/index.js';`
);
}
}
]
})),

}
]
},
/* compiler.js */
{
input: 'src/compiler/index.ts',
plugins: [
replace({
__VERSION__: pkg.version,
'process.env.NODE_DEBUG': false // appears inside the util package
preventAssignment: true,
values: {
__VERSION__: pkg.version,
'process.env.NODE_DEBUG': false // appears inside the util package
},
}),
{
resolveId(id) {
Expand All @@ -152,7 +129,7 @@ export default [
if (id === 'util') {
return require.resolve('./node_modules/util'); // just 'utils' would resolve this to the built-in module
}
}
},
},
resolve(),
commonjs({
Expand All @@ -177,6 +154,7 @@ export default [
],
external: is_publish
? []
: id => id === 'acorn' || id === 'magic-string' || id.startsWith('css-tree')
: (id) =>
id === 'acorn' || id === 'magic-string' || id.startsWith('css-tree')
}
];