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

[FEATURE] Babel all the things #225

Merged
merged 2 commits into from
Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"test": "./scripts/test.sh",
"lint": "cd packages/ember-auto-import && yarn lint"
},
"workspaces": ["packages/*", "types/*"],
"workspaces": [
"packages/*",
"types/*"
],
"resolutions": {
"@ember-decorators/babel-transforms/ember-cli-version-checker": "git+https://github.com/ef4/ember-cli-version-checker#0e33cbcd7faf17ec804b0c3fb64147b131a015de"
}
Expand Down
15 changes: 15 additions & 0 deletions packages/a-module-dependency/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function returnUndefined() {
// this should throw an error unless it's been transpiled
return foo;
let foo = 123;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, nice, I like this.

}

export default function aModuleDependency() {
try {
if (returnUndefined() === undefined) {
return 'module transpiled';
}
} catch (e) {
return 'module not transpiled';
}
}
4 changes: 4 additions & 0 deletions packages/a-module-dependency/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "a-module-dependency",
"version": "0.0.1"
}
4 changes: 4 additions & 0 deletions packages/ember-auto-import/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
"@babel/core": "^7.1.6",
"@babel/traverse": "^7.1.6",
"@babel/types": "^7.1.6",
"@embroider/core": "^0.4.3",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-template": "^6.26.0",
"babylon": "^6.18.0",
Expand All @@ -48,6 +50,7 @@
"resolve": "^1.7.1",
"rimraf": "^2.6.2",
"symlink-or-copy": "^1.2.0",
"typescript-memoize": "^1.0.0-alpha.3",
"walk-sync": "^0.3.3",
"webpack": "~4.28"
},
Expand All @@ -62,6 +65,7 @@
"@types/enhanced-resolve": "^3.0.6",
"@types/fs-extra": "^5.0.4",
"@types/js-string-escape": "^1.0.0",
"@types/jsdom": "^12.2.3",
"@types/lodash": "^4.14.110",
"@types/node": "^10.7.1",
"@types/pkg-up": "^2.0.0",
Expand Down
17 changes: 11 additions & 6 deletions packages/ember-auto-import/ts/auto-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ const protocol = '__ember_auto_import_protocol_v1__';
export default class AutoImport {
private primaryPackage: any;
private packages: Set<Package> = new Set();
private env: "development" | "test" | "production";
private env: 'development' | 'test' | 'production';
private consoleWrite: (msg: string) => void;
private analyzers: Map<Analyzer, Package> = new Map();
private bundles: BundleConfig;
private targets: unknown;

static lookup(appOrAddon: any): AutoImport {
let g = global as any;
Expand All @@ -38,6 +39,7 @@ export default class AutoImport {
this.packages.add(Package.lookup(hostContext));
let host = hostContext.app;
this.env = host.env;
this.targets = host.project.targets;
this.bundles = new BundleConfig(host);
if (!this.env) {
throw new Error('Bug in ember-auto-import: did not discover environment');
Expand Down Expand Up @@ -66,7 +68,7 @@ export default class AutoImport {
// decides which ones to include in which bundles
let splitter = new Splitter({
analyzers: this.analyzers,
bundles: this.bundles
bundles: this.bundles,
});

// The Bundler asks the splitter for deps it should include and
Expand All @@ -76,7 +78,8 @@ export default class AutoImport {
environment: this.env,
packages: this.packages,
consoleWrite: this.consoleWrite,
bundles: this.bundles
bundles: this.bundles,
targets: this.targets,
});
}

Expand All @@ -97,7 +100,8 @@ export default class AutoImport {
passthrough.set('lazy', this.bundles.lazyChunkPath);

return new Append(allAppTree, bundler, {
mappings, passthrough
mappings,
passthrough,
});
}

Expand Down Expand Up @@ -141,7 +145,8 @@ export default class AutoImport {
}

updateFastBootManifest(manifest: { vendorFiles: string[] }) {
manifest.vendorFiles.push(`${this.bundles.lazyChunkPath}/auto-import-fastboot.js`);
manifest.vendorFiles.push(
`${this.bundles.lazyChunkPath}/auto-import-fastboot.js`
);
}

}
86 changes: 50 additions & 36 deletions packages/ember-auto-import/ts/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,22 @@ import Plugin, { Tree } from 'broccoli-plugin';
import makeDebug from 'debug';
import WebpackBundler from './webpack';
import Splitter, { BundleDependencies } from './splitter';
import Package, { reloadDevPackages } from './package';
import Package, { reloadDevPackages, Options } from './package';
import { merge } from 'lodash';
import { join } from 'path';
import {
readFileSync,
writeFileSync,
emptyDirSync,
copySync,
} from 'fs-extra';
import { readFileSync, writeFileSync, emptyDirSync, copySync } from 'fs-extra';
import BundleConfig from './bundle-config';
import { Memoize } from 'typescript-memoize';

const debug = makeDebug('ember-auto-import:bundler');

export interface BundlerPluginOptions {
consoleWrite: (msg: string) => void;
environment: "development" | "test" | "production";
environment: 'development' | 'test' | 'production';
splitter: Splitter;
packages: Set<Package>;
bundles: BundleConfig;
targets: unknown;
}

export interface BuildResult {
Expand All @@ -41,25 +38,38 @@ export default class Bundler extends Plugin {
constructor(allAppTree: Tree, private options: BundlerPluginOptions) {
super([allAppTree], {
persistentOutput: true,
needsCache: true
needsCache: true,
});
}

private get publicAssetURL(): string | undefined {
// Only the app (not an addon) can customize the public asset URL, because
// it's an app concern.
@Memoize()
private get rootPackage(): Package {
let rootPackage = [...this.options.packages.values()].find(
pkg => !pkg.isAddon
);
if (rootPackage) {
let url = rootPackage.publicAssetURL;
if (url) {
if (url[url.length - 1] !== '/') {
url = url + '/';
}
return url;
if (!rootPackage) {
throw new Error(
`bug in ember-auto-import, there should always be a Package representing the app`
);
}
return rootPackage;
}

private get publicAssetURL(): string | undefined {
// Only the app (not an addon) can customize the public asset URL, because
// it's an app concern.
return this.rootPackage.publicAssetURL;
}

private get skipBabel(): Required<Options>['skipBabel'] {
let output: Required<Options>['skipBabel'] = [];
for (let pkg of this.options.packages) {
let skip = pkg.skipBabel;
if (skip) {
output = output.concat(skip);
}
}
return output;
}

get bundlerHook(): BundlerHook {
Expand All @@ -78,6 +88,8 @@ export default class Bundler extends Plugin {
extraWebpackConfig,
this.options.consoleWrite,
this.publicAssetURL,
this.skipBabel,
this.options.targets,
this.cachePath
);
}
Expand Down Expand Up @@ -111,29 +123,31 @@ export default class Bundler extends Plugin {
private addEntrypoints({ entrypoints, dir }: BuildResult) {
for (let bundle of this.options.bundles.names) {
if (entrypoints.has(bundle)) {
entrypoints
.get(bundle)!
.forEach(asset => {
copySync(join(dir, asset), join(this.outputPath, 'entrypoints', bundle, asset));
});
entrypoints.get(bundle)!.forEach(asset => {
copySync(
join(dir, asset),
join(this.outputPath, 'entrypoints', bundle, asset)
);
});
}
}
}

private addLazyAssets({ lazyAssets, dir }: BuildResult) {
let contents = lazyAssets.map(asset => {
// we copy every lazy asset into place here
let content = readFileSync(join(dir, asset));
writeFileSync(join(this.outputPath, 'lazy', asset), content);

// and then for JS assets, we also save a copy to put into the fastboot
// combined bundle. We don't want to include other things like WASM here
// that can't be concatenated.
if (/\.js$/i.test(asset)) {
return content;
}
let contents = lazyAssets
.map(asset => {
// we copy every lazy asset into place here
let content = readFileSync(join(dir, asset));
writeFileSync(join(this.outputPath, 'lazy', asset), content);

}).filter(Boolean);
// and then for JS assets, we also save a copy to put into the fastboot
// combined bundle. We don't want to include other things like WASM here
// that can't be concatenated.
if (/\.js$/i.test(asset)) {
return content;
}
})
.filter(Boolean);
writeFileSync(
join(this.outputPath, 'lazy', 'auto-import-fastboot.js'),
contents.join('\n')
Expand Down
13 changes: 12 additions & 1 deletion packages/ember-auto-import/ts/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface Options {
webpack?: Configuration;
publicAssetURL?: string;
forbidEval?: boolean;
skipBabel?: { package: string, semverRange?: string }[];
}

export default class Package {
Expand Down Expand Up @@ -156,6 +157,10 @@ export default class Package {
return this.autoImportOptions && this.autoImportOptions.webpack;
}

get skipBabel(): Options["skipBabel"] {
return this.autoImportOptions && this.autoImportOptions.skipBabel;
}

aliasFor(name: string): string {
return (
(this.autoImportOptions &&
Expand All @@ -170,7 +175,13 @@ export default class Package {
}

get publicAssetURL(): string | undefined {
return this.autoImportOptions && this.autoImportOptions.publicAssetURL;
let url = this.autoImportOptions && this.autoImportOptions.publicAssetURL;
if (url) {
if (url[url.length - 1] !== '/') {
url = url + '/';
}
}
return url;
}

get forbidsEval(): boolean {
Expand Down
46 changes: 44 additions & 2 deletions packages/ember-auto-import/ts/webpack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import webpack, { Configuration } from 'webpack';
import { join } from 'path';
import { join, dirname } from 'path';
import { mergeWith, flatten } from 'lodash';
import { writeFileSync, realpathSync } from 'fs';
import { compile, registerHelper } from 'handlebars';
Expand All @@ -8,6 +8,8 @@ import { BundleDependencies } from './splitter';
import { BundlerHook, BuildResult } from './bundler';
import BundleConfig from './bundle-config';
import { ensureDirSync } from 'fs-extra';
import { babelFilter } from '@embroider/core';
import { Options } from './package';

registerHelper('js-string-escape', jsStringEscape);

Expand Down Expand Up @@ -68,6 +70,8 @@ export default class WebpackBundler implements BundlerHook {
extraWebpackConfig: webpack.Configuration | undefined,
private consoleWrite: (message: string) => void,
private publicAssetURL: string | undefined,
private skipBabel: Required<Options>["skipBabel"],
private babelTargets: unknown,
tempArea: string
) {
// resolve the real path, because we're going to do path comparisons later
Expand Down Expand Up @@ -101,9 +105,17 @@ export default class WebpackBundler implements BundlerHook {
chunks: 'all'
}
},
resolveLoader: {
alias: {
// these loaders are our dependencies, not the app's dependencies. I'm
// not overriding the default loader resolution rules in case the app also
// wants to control those.
'babel-loader-8': require.resolve('babel-loader'),
}
},
module: {
noParse: (file) => file === join(this.stagingDir, 'l.js'),
rules: []
rules: [this.babelRule()]
},
node: false,
};
Expand All @@ -113,6 +125,36 @@ export default class WebpackBundler implements BundlerHook {
this.webpack = webpack(config);
}

private babelRule(): webpack.Rule {
let shouldTranspile = babelFilter(this.skipBabel);
let stagingDir = this.stagingDir;
return {
test(filename: string) {
// We don't apply babel to our own stagingDir (it contains only our own
// entrypoints that we wrote, and it can use `import()`, which we want
// to leave directly for webpack).
//
// And we otherwise defer to the `skipBabel` setting as implemented by
// `@embroider/core`.
return dirname(filename) !== stagingDir && shouldTranspile(filename);
},
use: {
loader: 'babel-loader-8',
options: {
presets: [
[
require.resolve('@babel/preset-env'),
{
modules: false,
targets: this.babelTargets
}
]
]
}
}
};
}

async build(bundleDeps: Map<string, BundleDependencies>) {
for (let [bundle, deps] of bundleDeps.entries()) {
this.writeEntryFile(bundle, deps);
Expand Down
1 change: 1 addition & 0 deletions packages/ember-auto-import/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"sourceMap": true,
"experimentalDecorators": true,
"strict": true
}
}
6 changes: 6 additions & 0 deletions packages/sample-babel7/app/controllers/application.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import Controller from '@ember/controller';
import { computed } from '@ember-decorators/object';
import aDependency from 'a-dependency';
import aModuleDependency from 'a-module-dependency';

export default class extends Controller {
@computed()
get result() {
return aDependency();
}

@computed()
get moduleResult() {
return aModuleDependency();
}
}
Loading