diff --git a/.babelignore b/.babelignore index f5a47ba77d..7cfbcb530a 100644 --- a/.babelignore +++ b/.babelignore @@ -2,3 +2,6 @@ packages/*/test/fixtures packages/*/lib packages/babel-standalone/babel.js +experimental/*/test/fixtures +experimental/*/lib +experimental/babel-preset-env-standalone/babel-preset-env.js diff --git a/.eslintignore b/.eslintignore index c4f3acc6e0..280c93cdbb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,6 +18,8 @@ experimental/*/test/fixtures experimental/*/test/tmp experimental/babel-preset-env/data experimental/babel-preset-env/test/debug-fixtures +experimental/babel-preset-env-standalone/babel-preset-env.js +experimental/babel-preset-env-standalone/babel-preset-env.min.js packages/babel-standalone/babel.js packages/babel-standalone/babel.min.js packages/babylon/build diff --git a/.gitignore b/.gitignore index ad624ca40a..a06f895a04 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,10 @@ package-lock.json /babel.sublime-workspace packages/babel-standalone/babel.js packages/babel-standalone/babel.min.js +/experimental/*/node_modules +/experimental/*/lib +experimental/babel-preset-env-standalone/babel-preset-env.js +experimental/babel-preset-env-standalone/babel-preset-env.min.js /codemods/*/lib /codemods/*/node_modules /packages/babylon/build diff --git a/Gulpfile.js b/Gulpfile.js index 867c73a3ce..3f8d25095c 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -3,9 +3,6 @@ const plumber = require("gulp-plumber"); const through = require("through2"); const chalk = require("chalk"); -const pump = require("pump"); -const uglify = require("gulp-uglify"); -const rename = require("gulp-rename"); const newer = require("gulp-newer"); const babel = require("gulp-babel"); const watch = require("gulp-watch"); @@ -13,11 +10,10 @@ const gutil = require("gulp-util"); const filter = require("gulp-filter"); const gulp = require("gulp"); const path = require("path"); -const merge = require("merge-stream"); -const RootMostResolvePlugin = require("webpack-dependency-suite") - .RootMostResolvePlugin; const webpack = require("webpack"); -const webpackStream = require("webpack-stream"); +const merge = require("merge-stream"); +const registerStandalonePackageTask = require("./scripts/gulp-tasks") + .registerStandalonePackageTask; const sources = ["codemods", "packages", "experimental"]; @@ -81,114 +77,40 @@ gulp.task("watch", ["build"], function() { }); }); -gulp.task("build-babel-standalone", cb => { - pump( - [ - gulp.src(__dirname + "/packages/babel-standalone/src/index.js"), - webpackBuild(), - gulp.dest(__dirname + "/packages/babel-standalone"), - uglify(), - rename({ extname: ".min.js" }), - gulp.dest(__dirname + "/packages/babel-standalone"), - ], - cb - ); -}); +registerStandalonePackageTask( + gulp, + "babel", + "Babel", + path.join(__dirname, "packages"), + require("./packages/babel-core/package.json").version +); -function webpackBuild() { - let version = require("./packages/babel-core/package.json").version; +const presetEnvWebpackPlugins = [ + new webpack.NormalModuleReplacementPlugin( + /\.\/available-plugins/, + require.resolve( + path.join( + __dirname, + "./experimental/babel-preset-env-standalone/src/available-plugins" + ) + ) + ), + new webpack.NormalModuleReplacementPlugin( + /caniuse-lite\/data\/regions\/.+/, + require.resolve( + path.join( + __dirname, + "./experimental/babel-preset-env-standalone/src/caniuse-lite-regions" + ) + ) + ), +]; - // If this build is part of a pull request, include the pull request number in - // the version number. - if (process.env.CIRCLE_PR_NUMBER) { - version += "+pr." + process.env.CIRCLE_PR_NUMBER; - } - - const config = { - module: { - rules: [ - { - test: /\.js$/, - include: /node_modules/, - loader: "babel-loader", - options: { - // Some of the node_modules may have their own "babel" section in - // their project.json (or a ".babelrc" file). We need to ignore - // those as we're using our own Babel options. - babelrc: false, - presets: [ - [ - "@babel/env", - { - loose: true, - exclude: ["transform-typeof-symbol"], - }, - ], - ], - }, - }, - { - test: /\.js$/, - exclude: /node_modules/, - loader: "babel-loader", - options: { - // Some of the node_modules may have their own "babel" section in - // their project.json (or a ".babelrc" file). We need to ignore - // those as we're using our own Babel options. - babelrc: false, - presets: [ - [ - "@babel/env", - { - loose: true, - exclude: ["transform-typeof-symbol"], - }, - ], - ["@babel/stage-0", { loose: true }], - ], - }, - }, - ], - // babylon is already bundled and does not require parsing - noParse: [/babylon\/lib/], - }, - node: { - // Mock Node.js modules that Babel require()s but that we don't - // particularly care about. - fs: "empty", - module: "empty", - net: "empty", - }, - output: { - filename: "babel.js", - library: "Babel", - libraryTarget: "umd", - }, - plugins: [ - new webpack.DefinePlugin({ - "process.env.NODE_ENV": '"production"', - BABEL_VERSION: JSON.stringify(version), - VERSION: JSON.stringify(version), - }), - /*new webpack.NormalModuleReplacementPlugin( - /..\/..\/package/, - "../../../../src/babel-package-shim" - ),*/ - new webpack.optimize.ModuleConcatenationPlugin(), - ], - resolve: { - plugins: [ - // Dedupe packages that are used across multiple plugins. - // This replaces DedupePlugin from Webpack 1.x - new RootMostResolvePlugin(__dirname, true), - ], - }, - }; - - return webpackStream(config, webpack); - // To write JSON for debugging: - /*return webpackStream(config, webpack, (err, stats) => { - require('gulp-util').log(stats.toString({colors: true})); - require('fs').writeFileSync('webpack-debug.json', JSON.stringify(stats.toJson())); - });*/ -} +registerStandalonePackageTask( + gulp, + "babel-preset-env", + "babelPresetEnv", + path.join(__dirname, "experimental"), + require("./experimental/babel-preset-env/package.json").version, + presetEnvWebpackPlugins +); diff --git a/Makefile b/Makefile index 018b2d5ba7..ac6ff78e40 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ build: clean ./node_modules/.bin/gulp build ifneq ("$(BABEL_ENV)", "cov") make build-standalone + make build-preset-env-standalone endif build-babylon: @@ -27,6 +28,9 @@ build-babylon: build-standalone: ./node_modules/.bin/gulp build-babel-standalone +build-preset-env-standalone: + ./node_modules/.bin/gulp build-babel-preset-env-standalone + build-dist: build cd packages/babel-polyfill; \ scripts/build-dist.sh diff --git a/circle.yml b/circle.yml index 31b3b4fddd..83af421507 100644 --- a/circle.yml +++ b/circle.yml @@ -2,6 +2,8 @@ general: artifacts: - "packages/babel-standalone/babel.js" - "packages/babel-standalone/babel.min.js" + - "experimental/babel-preset-env-standalone/babel-preset-env.js" + - "experimental/babel-preset-env-standalone/babel-preset-env.min.js" machine: node: @@ -25,3 +27,4 @@ test: # data for a JS file that's several megabytes large is bound to fail. Here, # we just run the babel-standalone test separately. - ./node_modules/mocha/bin/_mocha packages/babel-standalone/test/ --opts test/mocha.opts + - ./node_modules/mocha/bin/_mocha experimental/babel-preset-env-standalone/test/ --opts test/mocha.opts diff --git a/experimental/babel-preset-env-standalone/README.md b/experimental/babel-preset-env-standalone/README.md new file mode 100644 index 0000000000..4c001e3dd3 --- /dev/null +++ b/experimental/babel-preset-env-standalone/README.md @@ -0,0 +1,36 @@ +@babel/preset-env-standalone +================= + +@babel/preset-env-standalone is a standalone build of [@babel/preset-env](https://babeljs.io/docs/plugins/preset-env) for use in non-Node.js environments, including browsers. + +Installation +============ + +There are several ways to use @babel/preset-env-standalone. Pick whichever one you like: + +- Use it via UNPKG: https://unpkg.com/@babel/preset-env-standalone@7/babel-preset-env.min.js. This is a simple way to embed it on a webpage without having to do any other setup. +- Install via NPM: `npm install --save @babel/preset-env-standalone` +- Manually grab `babel-preset-env.js` and/or `babel-preset-env.min.js`: + * Download archived source code from the [GitHub releases page](https://github.com/babel/babel/releases). + * Unpack it. + * Grab `babel-preset-env.js` and/or `babel-preset-env.min.js` from the `experimental/babel-preset-env-standalone`. + +Usage +===== + +Load `babel-preset-env.js` or `babel-preset-env.min.js` in your environment, **along with babel-standalone**. This is important: You need to load Babel too! It will be registered as an available preset of the @babel/standalone. + +Then, just use it like any other preset: + +```js +Babel.transform(code, { + presets: [ + ["@babel/preset-env", { + "targets": { + "browsers": "last 1 safari version" + }, + useBuiltIns: "usage" + }] + ] +}); +``` diff --git a/experimental/babel-preset-env-standalone/package.json b/experimental/babel-preset-env-standalone/package.json new file mode 100644 index 0000000000..1ca7417957 --- /dev/null +++ b/experimental/babel-preset-env-standalone/package.json @@ -0,0 +1,38 @@ +{ + "name": "@babel/preset-env-standalone", + "version": "7.0.0-beta.5", + "description": "Standalone build of babel-prest-env for use in non-Node.js environments.", + "main": "babel-preset-env.js", + "files": [ + "babel-preset-env.js", + "babel-preset-env.min.js", + "src" + ], + "devDependencies": { + "@babel/plugin-transform-new-target": "7.0.0-beta.5", + "@babel/preset-env": "7.0.0-beta.5", + "@babel/standalone": "7.0.0-beta.5", + "mock-require": "^2.0.2" + }, + "keywords": [ + "babel", + "babel-preset-env", + "babeljs", + "6to5", + "transpile", + "preset", + "standalone", + "transpiler" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/babel/babel/issues" + }, + "homepage": "https://github.com/babel/babel/packages/babel-preset-env-standalone#readme", + "jest": { + "transformIgnorePatterns": [ + "/node_modules/", + "babel-preset-env.js" + ] + } +} diff --git a/experimental/babel-preset-env-standalone/src/available-plugins.js b/experimental/babel-preset-env-standalone/src/available-plugins.js new file mode 100644 index 0000000000..4828e353f1 --- /dev/null +++ b/experimental/babel-preset-env-standalone/src/available-plugins.js @@ -0,0 +1,13 @@ +import { availablePlugins, registerPlugin } from "@babel/standalone"; + +const notIncludedPlugins = { + "transform-new-target": require("@babel/plugin-transform-new-target"), +}; + +Object.keys(notIncludedPlugins).forEach(pluginName => { + if (!availablePlugins[pluginName]) { + registerPlugin(pluginName, notIncludedPlugins[pluginName]); + } +}); + +export default availablePlugins; diff --git a/experimental/babel-preset-env-standalone/src/caniuse-lite-regions.js b/experimental/babel-preset-env-standalone/src/caniuse-lite-regions.js new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/experimental/babel-preset-env-standalone/src/caniuse-lite-regions.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/experimental/babel-preset-env-standalone/src/index.js b/experimental/babel-preset-env-standalone/src/index.js new file mode 100644 index 0000000000..e02ce8176d --- /dev/null +++ b/experimental/babel-preset-env-standalone/src/index.js @@ -0,0 +1,8 @@ +/* global VERSION */ + +import { registerPreset } from "@babel/standalone"; +import babelPresetEnv from "@babel/preset-env"; + +registerPreset("env", babelPresetEnv); + +export const version = VERSION; diff --git a/experimental/babel-preset-env-standalone/test/babel-preset-env.js b/experimental/babel-preset-env-standalone/test/babel-preset-env.js new file mode 100644 index 0000000000..c61a67a93a --- /dev/null +++ b/experimental/babel-preset-env-standalone/test/babel-preset-env.js @@ -0,0 +1,57 @@ +const assert = require("assert"); +const mock = require("mock-require"); +const Babel = require("@babel/standalone/babel"); +mock("Babel", Babel); +require("../babel-preset-env"); + +describe("babel-preset-env-standalone", () => { + it("works w/o targets", () => { + const output = Babel.transform("const a = 1;", { + presets: ["env"], + }).code; + assert.equal(output, "var a = 1;"); + }); + + it("doesn't transpile `const` with chrome 60", () => { + const output = Babel.transform("const a = 1;", { + presets: [ + [ + "env", + { + targets: { + chrome: 60, + }, + }, + ], + ], + }).code; + assert.equal(output, "const a = 1;"); + }); + + it("transpiles `const` with chrome 60 and preset-es2015", () => { + const output = Babel.transform("const a = 1;", { + presets: [ + [ + "env", + { + targets: { + chrome: 60, + }, + }, + ], + "es2015", + ], + }).code; + assert.equal(output, "var a = 1;"); + }); + + it("uses transform-new-targets plugin", () => { + const output = Babel.transform("function Foo() {new.target}", { + presets: ["env"], + }).code; + assert.equal( + output, + "function Foo() {\n this instanceof Foo ? this.constructor : void 0;\n}", + ); + }); +}); diff --git a/scripts/_get-test-directories.sh b/scripts/_get-test-directories.sh index 22dff73213..c11573ad5a 100755 --- a/scripts/_get-test-directories.sh +++ b/scripts/_get-test-directories.sh @@ -11,7 +11,7 @@ for source in "${sources[@]}"; do continue fi # Exclude babel-standalone from coverage runs - if [ "$TEST_TYPE" = "cov" ] && [ `basename $f` = 'babel-standalone' ]; then + if [ "$TEST_TYPE" = "cov" ] && [[ `basename $f` = 'babel-standalone' || `basename $f` = 'babel-preset-env-standalone' ]]; then continue fi diff --git a/scripts/gulp-tasks.js b/scripts/gulp-tasks.js new file mode 100644 index 0000000000..2e4891efb4 --- /dev/null +++ b/scripts/gulp-tasks.js @@ -0,0 +1,164 @@ +"use strict"; + +/** + * This file contains the Gulp tasks for babel-standalone. Note that + * babel-standalone is compiled using Webpack, and performs its own Babel + * compilation of all the JavaScript files. This is because it targets web + * browsers, so more transforms are needed than the regular Babel builds that + * only target Node.js. + * + * The tasks in this file are designed to be reusable, so that they can be used + * to make standalone builds of other Babel plugins/presets (such as babel-minify) + */ + +const path = require("path"); +const pump = require("pump"); +const rename = require("gulp-rename"); +const RootMostResolvePlugin = require("webpack-dependency-suite") + .RootMostResolvePlugin; +const webpack = require("webpack"); +const webpackStream = require("webpack-stream"); +const uglify = require("gulp-uglify"); + +function webpackBuild(opts) { + const plugins = opts.plugins || []; + let babelVersion = require("../packages/babel-core/package.json").version; + let version = opts.version || babelVersion; + // If this build is part of a pull request, include the pull request number in + // the version number. + if (process.env.CIRCLE_PR_NUMBER) { + const prVersion = "+pr." + process.env.CIRCLE_PR_NUMBER; + babelVersion += prVersion; + version += prVersion; + } + + const config = { + module: { + rules: [ + { + test: /\.js$/, + include: /node_modules/, + loader: "babel-loader", + options: { + // Some of the node_modules may have their own "babel" section in + // their project.json (or a ".babelrc" file). We need to ignore + // those as we're using our own Babel options. + babelrc: false, + presets: [ + [ + "@babel/env", + { + loose: true, + exclude: ["transform-typeof-symbol"], + }, + ], + ], + }, + }, + { + test: /\.js$/, + exclude: /node_modules/, + loader: "babel-loader", + options: { + // Some of the node_modules may have their own "babel" section in + // their project.json (or a ".babelrc" file). We need to ignore + // those as we're using our own Babel options. + babelrc: false, + presets: [ + [ + "@babel/env", + { + loose: true, + exclude: ["transform-typeof-symbol"], + }, + ], + ["@babel/stage-0", { loose: true }], + ], + }, + }, + ], + // babylon is already bundled and does not require parsing + noParse: [/babylon\/lib/], + }, + node: { + // Mock Node.js modules that Babel require()s but that we don't + // particularly care about. + fs: "empty", + module: "empty", + net: "empty", + }, + output: { + filename: opts.filename, + library: opts.library, + libraryTarget: "umd", + }, + plugins: [ + new webpack.DefinePlugin({ + "process.env.NODE_ENV": '"production"', + "process.env": JSON.stringify({ NODE_ENV: "production" }), + BABEL_VERSION: JSON.stringify(babelVersion), + VERSION: JSON.stringify(version), + }), + /*new webpack.NormalModuleReplacementPlugin( + /..\/..\/package/, + "../../../../src/babel-package-shim" + ),*/ + new webpack.optimize.ModuleConcatenationPlugin(), + ].concat(plugins), + resolve: { + plugins: [ + // Dedupe packages that are used across multiple plugins. + // This replaces DedupePlugin from Webpack 1.x + new RootMostResolvePlugin(__dirname, true), + ], + }, + }; + + if (opts.library !== "Babel") { + config.externals = { + "@babel/standalone": "Babel", + }; + } + + return webpackStream(config, webpack); + // To write JSON for debugging: + /*return webpackStream(config, webpack, (err, stats) => { + require('gulp-util').log(stats.toString({colors: true})); + require('fs').writeFileSync('webpack-debug.json', JSON.stringify(stats.toJson())); + });*/ +} + +function registerStandalonePackageTask( + gulp, + name, + exportName, + pathname, + version, + plugins +) { + const standaloneName = name + "-standalone"; + const standalonePath = path.join(pathname, standaloneName); + gulp.task("build-" + standaloneName, cb => { + pump( + [ + gulp.src(path.join(standalonePath, "src/index.js")), + webpackBuild({ + filename: name + ".js", + library: exportName, + version, + plugins, + }), + gulp.dest(standalonePath), + uglify(), + rename({ extname: ".min.js" }), + gulp.dest(standalonePath), + ], + cb + ); + }); +} + +module.exports = { + webpackBuild: webpackBuild, + registerStandalonePackageTask: registerStandalonePackageTask, +};