Skip to content

Commit

Permalink
minify scripts with sourcemapping
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 committed Feb 18, 2019
1 parent 06625b4 commit 49a35b1
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 10 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,12 @@ export class AppBuilder<TreeNames> {
let concat = new SourceMapConcat({
outputFile: join(this.root, asset.relativePath),
mapCommentType: asset.relativePath.endsWith('.js') ? 'line' : 'block',
baseDir: this.root,
});
for (let source of asset.sources) {
switch (source.kind) {
case 'on-disk':
concat.addFile(source.sourcePath);
concat.addFile(relative(this.root, source.sourcePath));
break;
case 'in-memory':
if (typeof source.source !== 'string') {
Expand Down
2 changes: 2 additions & 0 deletions packages/webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"lodash": "^4.17.10",
"mini-css-extract-plugin": "^0.4.3",
"pkg-up": "^2.0.0",
"source-map-url": "^0.4.0",
"style-loader": "^0.23.0",
"terser": "^3.16.1",
"thread-loader": "^1.2.0",
"webpack": "^4.17.1"
},
Expand Down
61 changes: 53 additions & 8 deletions packages/webpack/src/ember-webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import { PackagerInstance, AppMeta, Packager, PackageCache } from "@embroider/core";
import webpack, { Configuration } from 'webpack';
import { readFileSync, writeFileSync, copySync, realpathSync, ensureDirSync, Stats, statSync } from 'fs-extra';
import { readFileSync, writeFileSync, copySync, realpathSync, ensureDirSync, Stats, statSync, readJsonSync } from 'fs-extra';
import { join, dirname, relative, resolve } from 'path';
import { JSDOM } from 'jsdom';
import isEqual from 'lodash/isEqual';
Expand All @@ -20,6 +20,11 @@ import partition from 'lodash/partition';
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import Placeholder from './html-placeholder';

// This is a type-only import, so it gets compiled away. At runtime, we load
// terser lazily so it's only loaded for production builds that use it. Don't
// add any non-type-only imports here.
import { MinifyOptions } from 'terser';

class HTMLEntrypoint {
private dom: JSDOM;
private dir: string;
Expand Down Expand Up @@ -126,7 +131,7 @@ const Webpack: Packager<Options> = class Webpack implements PackagerInstance {
let appInfo = this.examineApp();
let webpack = this.getWebpack(appInfo);
let stats = this.summarizeStats(await this.runWebpack(webpack));
this.writeFiles(stats, appInfo);
await this.writeFiles(stats, appInfo);
}

private examineApp(): AppInfo {
Expand Down Expand Up @@ -263,36 +268,76 @@ const Webpack: Packager<Options> = class Webpack implements PackagerInstance {
return this.lastWebpack = webpack(config);
}

private writeFiles(stats: StatSummary, { entrypoints, otherAssets }: AppInfo) {
private async writeScript(script: string, written: Set<string>) {
if (this.mode !== 'production') {
this.copyThrough(script);
return script;
}

// loading these lazily here so they never load in non-production builds.
// The node cache will ensures we only load them once.
const [Terser, srcURL] = await Promise.all([import('terser'), import('source-map-url')]);

let inCode = readFileSync(join(this.pathToVanillaApp, script), 'utf8');
let terserOpts: MinifyOptions = {};
let fileRelativeSourceMapURL;
let appRelativeSourceMapURL;
if (srcURL.default.existsIn(inCode)) {
fileRelativeSourceMapURL = srcURL.default.getFrom(inCode)!;
appRelativeSourceMapURL = join(dirname(script), fileRelativeSourceMapURL);
terserOpts.sourceMap = {
content: readJsonSync(join(this.pathToVanillaApp, appRelativeSourceMapURL)),
url: fileRelativeSourceMapURL
};
}
let { code: outCode, map: outMap } = Terser.default.minify(inCode, terserOpts);
writeFileSync(join(this.outputPath, script), outCode);
written.add(script);
if (appRelativeSourceMapURL && outMap) {
writeFileSync(join(this.outputPath, appRelativeSourceMapURL), outMap);
written.add(appRelativeSourceMapURL);
}
return script;
}

private async writeStyle(style: string) {
this.copyThrough(style);
return style;
}

private async writeFiles(stats: StatSummary, { entrypoints, otherAssets }: AppInfo) {
// we're doing this ourselves because I haven't seen a webpack 4 HTML plugin
// that handles multiple HTML entrypoints correctly.

let written: Set<string> = new Set();

// scripts (as opposed to modules) and stylesheets (as opposed to CSS
// modules that are imported from JS modules) get passed through without
// going through webpack.
let bundles = new Map(stats.entrypoints);
for (let entrypoint of entrypoints) {
for (let script of entrypoint.scripts) {
if (!bundles.has(script)) {
bundles.set(script, [script]);
this.copyThrough(script);
bundles.set(script, [await this.writeScript(script, written)]);
}
}
for (let style of entrypoint.styles) {
if (!bundles.has(style)) {
bundles.set(style, [style]);
this.copyThrough(style);
bundles.set(style, [await this.writeStyle(style, written)]);
}
}
}

for (let entrypoint of entrypoints) {
ensureDirSync(dirname(join(this.outputPath, entrypoint.filename)));
writeFileSync(join(this.outputPath, entrypoint.filename), entrypoint.render(bundles), 'utf8');
written.add(entrypoint.filename);
}

for (let relativePath of otherAssets) {
this.copyThrough(relativePath);
if (!written.has(relativePath)) {
this.copyThrough(relativePath);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion types/fast-sourcemap-concat/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ declare module 'fast-sourcemap-concat' {
export default class {
constructor(opts: {
outputFile?: string,
mapCommentType?: "line" | "block"
mapCommentType?: "line" | "block",
baseDir?: string,
});
addFile(filename: string): void;
addSpace(source: string): void;
Expand Down
10 changes: 10 additions & 0 deletions types/source-map-url/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
declare module 'source-map-url' {
interface SrcURL {
getFrom(code: string): string | undefined;
existsIn(code: string): boolean;
removeFrom(code: string): string;
insertBefore(code: string, otherString: string): string;
}
const srcURL: SrcURL;
export default srcURL;
}

0 comments on commit 49a35b1

Please sign in to comment.