Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Commit e27ba3b

Browse files
committed
Extend internal rollup plugin to replace extract_css
1 parent 2135b2f commit e27ba3b

File tree

14 files changed

+471
-348
lines changed

14 files changed

+471
-348
lines changed

package-lock.json

-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
"puppeteer": "^5.0.0",
5656
"require-relative": "^0.8.7",
5757
"rollup": "^2.21.0",
58-
"rollup-dependency-tree": "^0.0.2",
5958
"rollup-plugin-svelte": "^5.1.0",
6059
"rollup-plugin-typescript2": "^0.27.1",
6160
"sade": "^1.6.1",

runtime/src/server/middleware/get_page_handler.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ export function get_page_handler(
5050
shimport: string | null,
5151
assets: Record<string, string | string[]>,
5252
dependencies: Record<string, string[]>,
53-
css: {
54-
main: string | null,
55-
chunks: Record<string, string[]>
56-
},
5753
legacy_assets?: Record<string, string>
5854
} = get_build_info();
5955

@@ -73,17 +69,9 @@ export function get_page_handler(
7369

7470
let es6_preload = false;
7571
if (build_info.bundler === 'rollup') {
76-
7772
es6_preload = true;
78-
7973
const route = page.parts[page.parts.length - 1].file;
80-
81-
// JS
8274
preload_files = preload_files.concat(build_info.dependencies[route]);
83-
84-
// CSS
85-
preload_files = preload_files.concat(build_info.css.main);
86-
preload_files = preload_files.concat(build_info.css.chunks[route]);
8775
}
8876

8977
const link = preload_files
@@ -323,16 +311,17 @@ export function get_page_handler(
323311

324312
// TODO make this consistent across apps
325313
// TODO embed build_info in placeholder.ts
326-
if (build_info.css && build_info.css.main) {
314+
if (build_info.dependencies) {
327315
const css_chunks = new Set();
328-
if (build_info.css.main) css_chunks.add(build_info.css.main);
329316
page.parts.forEach(part => {
330317
if (!part) return;
331-
const css_chunks_for_part = build_info.css.chunks[part.file];
318+
const css_chunks_for_part = build_info.dependencies[part.file];
332319

333320
if (css_chunks_for_part) {
334321
css_chunks_for_part.forEach(chunk => {
335-
css_chunks.add(chunk);
322+
if (chunk.endsWith('.css')) {
323+
css_chunks.add(chunk);
324+
}
336325
});
337326
}
338327
});

src/api/build.ts

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import minify_html from './utils/minify_html';
44
import { create_compilers, create_app, create_manifest_data, create_serviceworker_manifest } from '../core';
55
import { copy_shimport } from './utils/copy_shimport';
66
import read_template from '../core/read_template';
7+
import inject_resources from '../core/create_compilers/inject';
78
import { CompileResult } from '../core/create_compilers/interfaces';
89
import { noop } from './utils/noop';
910
import validate_bundler from './utils/validate_bundler';
@@ -104,8 +105,14 @@ export async function build({
104105
}
105106

106107
fs.writeFileSync(path.join(dest, 'build.json'), JSON.stringify(build_info));
108+
if (bundler === 'rollup') {
109+
inject_resources(path.join(dest, 'build.json'), path.join(dest, 'client'));
110+
}
107111

108112
const server_stats = await server.compile();
113+
if (bundler === 'rollup') {
114+
inject_resources(path.join(dest, 'build.json'), path.join(dest, 'server'));
115+
}
109116
oncompile({
110117
type: 'server',
111118
result: server_stats

src/api/dev.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as ports from 'port-authority';
66
import { EventEmitter } from 'events';
77
import { create_manifest_data, create_app, create_compilers, create_serviceworker_manifest } from '../core';
88
import { Compiler, Compilers } from '../core/create_compilers';
9+
import inject_resources from '../core/create_compilers/inject';
910
import { CompileResult } from '../core/create_compilers/interfaces';
1011
import Deferred from './utils/Deferred';
1112
import validate_bundler from './utils/validate_bundler';
@@ -233,6 +234,9 @@ class Watcher extends EventEmitter {
233234
},
234235

235236
handle_result: (result: CompileResult) => {
237+
if (this.bundler === 'rollup') {
238+
inject_resources(path.join(this.dirs.dest, 'build.json'), path.join(this.dirs.dest, 'server'));
239+
}
236240
deferred.promise.then(() => {
237241
const restart = () => {
238242
this.crashed = false;
@@ -333,11 +337,13 @@ class Watcher extends EventEmitter {
333337
handle_result: (result: CompileResult) => {
334338
fs.writeFileSync(
335339
path.join(dest, 'build.json'),
336-
337-
// TODO should be more explicit that to_json has effects
338340
JSON.stringify(result.to_json(manifest_data, this.dirs), null, ' ')
339341
);
340342

343+
if (this.bundler === 'rollup') {
344+
inject_resources(path.join(this.dirs.dest, 'build.json'), path.join(this.dirs.dest, 'client'));
345+
}
346+
341347
const client_files = result.chunks.map(chunk => `client/${chunk.file}`);
342348

343349
create_serviceworker_manifest({

src/core/create_compilers/RollupCompiler.ts

+133-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,49 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import color from 'kleur';
34
import relative from 'require-relative';
4-
import { InputOption, RollupError } from 'rollup';
5+
import {
6+
InputOption,
7+
PluginContext,
8+
TransformResult,
9+
NormalizedInputOptions,
10+
NormalizedOutputOptions,
11+
RollupError,
12+
OutputBundle,
13+
OutputChunk
14+
} from 'rollup';
15+
import { ChunkResolver } from './chunk';
16+
import { chunk_content_from_modules, extract_sourcemap, emit_code_and_sourcemap } from './code';
517
import { CompileResult } from './interfaces';
618
import RollupResult from './RollupResult';
719

820
const stderr = console.error.bind(console);
921

1022
let rollup: any;
1123

24+
const get_entry_point_output_chunk = (bundle: OutputBundle, entry_point?: string) => {
25+
if (entry_point === undefined) {
26+
throw new Error("Internal error: entry_point cannot be undefined");
27+
}
28+
29+
let entry_point_output_chunk: OutputChunk;
30+
for (const chunk of Object.values(bundle)) {
31+
if ((chunk as OutputChunk).facadeModuleId === entry_point) {
32+
entry_point_output_chunk = chunk as OutputChunk;
33+
}
34+
}
35+
36+
if (!entry_point_output_chunk) {
37+
throw new Error(`Internal error: No chunk for entry point: ${entry_point} in: ${Object.keys(bundle)}`);
38+
}
39+
40+
if (entry_point_output_chunk.type !== 'chunk') {
41+
throw new Error(`Internal error: Wrong type for entry point chunk: ${entry_point} in: ${Object.keys(bundle)}`);
42+
}
43+
44+
return entry_point_output_chunk;
45+
};
46+
1247
export default class RollupCompiler {
1348
_: Promise<any>;
1449
_oninvalid: (filename: string) => void;
@@ -18,6 +53,7 @@ export default class RollupCompiler {
1853
errors: any[];
1954
chunks: any[];
2055
css_files: Array<{ id: string; code: string }>;
56+
dependencies: Record<string, string[]>;
2157

2258
constructor(config: any) {
2359
this._ = this.get_config(config);
@@ -26,23 +62,113 @@ export default class RollupCompiler {
2662
this.errors = [];
2763
this.chunks = [];
2864
this.css_files = [];
65+
this.dependencies = {};
2966
}
3067

3168
async get_config(mod: any) {
69+
let entry_point: string | undefined;
70+
71+
const that = this;
72+
const sourcemap = mod.output.sourcemap;
73+
3274
// TODO this is hacky, and doesn't need to apply to all three compilers
3375
(mod.plugins || (mod.plugins = [])).push({
3476
name: 'sapper-internal',
35-
options: (opts: any) => {
36-
this.input = opts.input;
77+
options(opts: any) {
78+
that.input = opts.input;
79+
},
80+
buildStart(this: PluginContext, options: NormalizedInputOptions): void {
81+
const input = options.input;
82+
const inputs: Array<{alias: string, file: string}> = [];
83+
84+
if (typeof input === 'string') {
85+
inputs.push({alias: 'main', file: input});
86+
} else if (Array.isArray(input)) {
87+
inputs.push(...input.map(file => ({file, alias: file})));
88+
} else {
89+
for (const alias in input) {
90+
inputs.push({file: input[alias], alias});
91+
}
92+
}
93+
if (!entry_point) {
94+
entry_point = inputs[0].file;
95+
}
3796
},
38-
renderChunk: (code: string, chunk: any) => {
39-
this.chunks.push(chunk);
97+
renderChunk(code: string, chunk: any) {
98+
that.chunks.push(chunk);
4099
},
41-
transform: (code: string, id: string) => {
100+
transform(code: string, id: string): TransformResult {
101+
// TODO: see if we can remove after release of https://github.com/sveltejs/rollup-plugin-svelte/pull/72
42102
if (/\.css$/.test(id)) {
43-
this.css_files.push({ id, code });
103+
that.css_files.push({ id, code });
44104
return {code: '', moduleSideEffects: 'no-treeshake'};
45105
}
106+
},
107+
async generateBundle(this: PluginContext, options: NormalizedOutputOptions, bundle: OutputBundle): Promise<void> {
108+
const entry_point_output_chunk = get_entry_point_output_chunk(bundle, entry_point);
109+
110+
const chunk_resolver = new ChunkResolver<OutputChunk>({
111+
id: chunk => chunk.fileName,
112+
resolve_id: chunk_file => {
113+
const oc = bundle[chunk_file];
114+
return oc && oc.type === 'chunk' ? oc : undefined;
115+
},
116+
internals: chunk => ({
117+
id: chunk.fileName,
118+
facadeId: chunk.facadeModuleId,
119+
name: chunk.name,
120+
file_name: chunk.fileName,
121+
dep_names: chunk === entry_point_output_chunk ? [...chunk.imports] : [...chunk.imports, ...chunk.dynamicImports],
122+
manifest: Object.keys(chunk.modules),
123+
type: options.format === 'es' ? 'module' : 'script'
124+
}),
125+
module_imports: js_module => {
126+
const module_info = this.getModuleInfo(js_module);
127+
return [
128+
...module_info.importedIds,
129+
...module_info.dynamicallyImportedIds
130+
].filter(id => /\.css$/.test(id));
131+
},
132+
chunks_from_modules: (chunk, css_modules) => {
133+
const name = chunk.name + '.css';
134+
const file_name = emit_code_and_sourcemap({
135+
sourcemap,
136+
output: chunk_content_from_modules(
137+
css_modules,
138+
css_module => {
139+
const f = that.css_files.find(file => file.id === css_module);
140+
return f && extract_sourcemap(f.code, css_module);
141+
}
142+
),
143+
sourcemap_url_prefix: '',
144+
output_file_name: name,
145+
emit: (filename: string, source: string | Uint8Array) => {
146+
const moduleid = this.emitFile({ name: filename, type: 'asset', source });
147+
const file = this.getFileName(moduleid);
148+
return file;
149+
}
150+
});
151+
152+
return [{
153+
id: file_name,
154+
facadeId: chunk.facadeModuleId,
155+
name,
156+
file_name,
157+
manifest: css_modules,
158+
dep_names: []
159+
}];
160+
}
161+
});
162+
163+
const output_chunks = Object.values(bundle).filter(output => output.type === 'chunk') as OutputChunk[];
164+
const chunks = await Promise.all(output_chunks.map(chunk => chunk_resolver.resolve_chunk(chunk)));
165+
const dependencies = {};
166+
for (const chunk of chunks) {
167+
if (chunk.facadeId) {
168+
dependencies[chunk.facadeId] = Array.from(chunk.transitive_deps).map(dep => dep.file_name);
169+
}
170+
}
171+
that.dependencies = dependencies;
46172
}
47173
});
48174

src/core/create_compilers/RollupResult.ts

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import * as path from 'path';
22
import colors from 'kleur';
33
import pb from 'pretty-bytes';
4-
import transitiveDeps from 'rollup-dependency-tree';
54
import RollupCompiler from './RollupCompiler';
6-
import extract_css from './extract_css';
75
import { left_pad, normalize_path } from '../../utils';
86
import { CompileResult, BuildInfo, CompileError, Chunk, CssFile } from './interfaces';
97
import { ManifestData, Dirs } from '../../interfaces';
@@ -17,10 +15,6 @@ export default class RollupResult implements CompileResult {
1715
assets: Record<string, string>;
1816
dependencies: Record<string, string[]>;
1917
css_files: CssFile[];
20-
css: {
21-
main: string;
22-
chunks: Record<string, string[]>;
23-
};
2418
sourcemap: boolean | 'inline';
2519
summary: string;
2620

@@ -38,6 +32,7 @@ export default class RollupResult implements CompileResult {
3832
}));
3933

4034
this.css_files = compiler.css_files;
35+
this.dependencies = compiler.dependencies;
4136

4237
this.assets = {};
4338

@@ -55,8 +50,6 @@ export default class RollupResult implements CompileResult {
5550
}
5651
}
5752

58-
this.dependencies = transitiveDeps(compiler.chunks);
59-
6053
this.summary = compiler.chunks.map(chunk => {
6154
const size_color = chunk.code.length > 150000 ? colors.bold().red : chunk.code.length > 50000 ? colors.bold().yellow : colors.bold().white;
6255
const size_label = left_pad(pb(chunk.code.length), 10);
@@ -91,20 +84,21 @@ export default class RollupResult implements CompileResult {
9184
}).join('\n');
9285
}
9386

94-
to_json(manifest_data: ManifestData, dirs: Dirs): BuildInfo {
87+
relative_dependencies(routes_dir: string) {
9588
const dependencies = {};
9689
Object.entries(this.dependencies).forEach(([key, value]) => {
97-
dependencies[path.relative(dirs.routes, key)] = value;
90+
dependencies[normalize_path(path.relative(routes_dir, key)).replace(/\\/g, '/')] = value;
9891
});
92+
return dependencies;
93+
}
9994

95+
to_json(manifest_data: ManifestData, dirs: Dirs): BuildInfo {
96+
const dependencies = (this.relative_dependencies(dirs.routes));
10097
return {
10198
bundler: 'rollup',
10299
shimport: shimport_version,
103100
assets: this.assets,
104-
dependencies,
105-
106-
// TODO extract_css has side-effects that don't belong in a method called to_json
107-
css: extract_css(this, manifest_data.components, dirs, this.sourcemap)
101+
dependencies
108102
};
109103
}
110104

src/core/create_compilers/WebpackResult.ts

+1-15
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,7 @@ export default class WebpackResult implements CompileResult {
6464
return {
6565
bundler: 'webpack',
6666
shimport: null, // webpack has its own loader
67-
assets: this.assets,
68-
css: {
69-
main: extract_css(this.assets.main),
70-
chunks: manifest_data.components
71-
.reduce((chunks: Record<string, string[]>, component: PageComponent) => {
72-
const css_dependencies = [];
73-
const css = extract_css(this.assets[component.name]);
74-
75-
if (css) css_dependencies.push(css);
76-
77-
chunks[component.file] = css_dependencies;
78-
79-
return chunks;
80-
}, {})
81-
}
67+
assets: this.assets
8268
};
8369
}
8470

0 commit comments

Comments
 (0)