├── .babelrc ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.sw.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package.json ├── src ├── App.vue ├── components │ ├── Controls.vue │ ├── Editor.vue │ ├── Errors.vue │ ├── Layout.vue │ └── Slider.vue ├── main.js ├── store │ ├── babel-worker.js │ ├── buffer-utils.js │ ├── byte-utils.js │ └── index.js └── sw.js ├── static └── .gitkeep └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | "transform-runtime" 12 | ], 13 | "comments": false 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: { 5 | // to edit target browsers: use "browserlist" field in package.json 6 | autoprefixer: {} 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at me@boopathi.in. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Boopathi Rajaa 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # babel-time-travel 2 | 3 | > Timetravel interface for babel transformations 4 | 5 | ## Try it out 6 | 7 | https://babel-time-travel.boopathi.in/ 8 | 9 | ## Build Setup 10 | 11 | ``` bash 12 | # install dependencies 13 | yarn 14 | 15 | # serve with hot reload at localhost:8080 16 | yarn dev 17 | 18 | # build for production with minification 19 | yarn build 20 | 21 | # build for production and view the bundle analyzer report 22 | yarn build --report 23 | ``` 24 | 25 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 26 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | require("./check-versions")(); 2 | 3 | process.env.NODE_ENV = "production"; 4 | 5 | var ora = require("ora"); 6 | var rm = require("rimraf"); 7 | var path = require("path"); 8 | var chalk = require("chalk"); 9 | var webpack = require("webpack"); 10 | var config = require("../config"); 11 | var webpackConfig = require("./webpack.prod.conf"); 12 | 13 | var spinner = ora("building for production..."); 14 | spinner.start(); 15 | 16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 17 | if (err) throw err; 18 | webpack(webpackConfig, function(err, multistats) { 19 | spinner.stop(); 20 | if (err) throw err; 21 | 22 | for (const stats of multistats.stats) { 23 | process.stdout.write( 24 | stats.toString({ 25 | colors: true, 26 | modules: false, 27 | children: false, 28 | chunks: false, 29 | chunkModules: false 30 | }) + "\n\n" 31 | ); 32 | } 33 | 34 | console.log(chalk.cyan(" Build complete.\n")); 35 | console.log( 36 | chalk.yellow( 37 | " Tip: built files are meant to be served over an HTTP server.\n" + 38 | " Opening index.html over file:// won't work.\n" 39 | ) 40 | ); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require("chalk"); 2 | var semver = require("semver"); 3 | var packageConfig = require("../package.json"); 4 | var shell = require("shelljs"); 5 | function exec(cmd) { 6 | return require("child_process").execSync(cmd).toString().trim(); 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: "node", 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | } 15 | ]; 16 | 17 | if (shell.which("npm")) { 18 | versionRequirements.push({ 19 | name: "npm", 20 | currentVersion: exec("npm --version"), 21 | versionRequirement: packageConfig.engines.npm 22 | }); 23 | } 24 | 25 | module.exports = function() { 26 | var warnings = []; 27 | for (var i = 0; i < versionRequirements.length; i++) { 28 | var mod = versionRequirements[i]; 29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 30 | warnings.push( 31 | mod.name + 32 | ": " + 33 | chalk.red(mod.currentVersion) + 34 | " should be " + 35 | chalk.green(mod.versionRequirement) 36 | ); 37 | } 38 | } 39 | 40 | if (warnings.length) { 41 | console.log(""); 42 | console.log( 43 | chalk.yellow( 44 | "To use this template, you must update following to modules:" 45 | ) 46 | ); 47 | console.log(); 48 | for (var i = 0; i < warnings.length; i++) { 49 | var warning = warnings[i]; 50 | console.log(" " + warning); 51 | } 52 | console.log(); 53 | process.exit(1); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require("eventsource-polyfill"); 3 | var hotClient = require("webpack-hot-middleware/client?noInfo=true&reload=true"); 4 | 5 | hotClient.subscribe(function(event) { 6 | if (event.action === "reload") { 7 | window.location.reload(); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | require("./check-versions")(); 2 | 3 | var config = require("../config"); 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV); 6 | } 7 | 8 | var opn = require("opn"); 9 | var path = require("path"); 10 | var express = require("express"); 11 | var webpack = require("webpack"); 12 | var proxyMiddleware = require("http-proxy-middleware"); 13 | var webpackConfig = require("./webpack.dev.conf"); 14 | 15 | // default port where dev server listens for incoming traffic 16 | var port = process.env.PORT || config.dev.port; 17 | // automatically open browser, if not set will be false 18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser; 19 | // Define HTTP proxies to your custom API backend 20 | // https://github.com/chimurai/http-proxy-middleware 21 | var proxyTable = config.dev.proxyTable; 22 | 23 | var app = express(); 24 | var compiler = webpack(webpackConfig[0]); 25 | var swCompiler = webpack(webpackConfig[1]); 26 | 27 | var swDevMiddleware = require("webpack-dev-middleware")(swCompiler, { 28 | publicPath: webpackConfig[1].output.publicPath, 29 | quiet: true, 30 | headers: { 31 | "Content-Type": "application/javascript" 32 | } 33 | }); 34 | 35 | var devMiddleware = require("webpack-dev-middleware")(compiler, { 36 | publicPath: webpackConfig[0].output.publicPath, 37 | quiet: true 38 | }); 39 | 40 | var hotMiddleware = require("webpack-hot-middleware")(compiler, { 41 | log: () => {} 42 | }); 43 | // force page reload when html-webpack-plugin template changes 44 | compiler.plugin("compilation", function(compilation) { 45 | compilation.plugin("html-webpack-plugin-after-emit", function(data, cb) { 46 | hotMiddleware.publish({ action: "reload" }); 47 | cb(); 48 | }); 49 | }); 50 | 51 | // proxy api requests 52 | Object.keys(proxyTable).forEach(function(context) { 53 | var options = proxyTable[context]; 54 | if (typeof options === "string") { 55 | options = { target: options }; 56 | } 57 | app.use(proxyMiddleware(options.filter || context, options)); 58 | }); 59 | 60 | // handle fallback for HTML5 history API 61 | app.use(require("connect-history-api-fallback")()); 62 | 63 | // serve webpack bundle output 64 | app.use(devMiddleware); 65 | 66 | // serve webpack for sw bundle output 67 | app.use(swDevMiddleware); 68 | 69 | // enable hot-reload and state-preserving 70 | // compilation error display 71 | app.use(hotMiddleware); 72 | 73 | // serve pure static assets 74 | var staticPath = path.posix.join( 75 | config.dev.assetsPublicPath, 76 | config.dev.assetsSubDirectory 77 | ); 78 | app.use(staticPath, express.static("./static")); 79 | 80 | var uri = "http://localhost:" + port; 81 | 82 | var _resolve; 83 | var readyPromise = new Promise(resolve => { 84 | _resolve = resolve; 85 | }); 86 | 87 | console.log("> Starting dev server..."); 88 | devMiddleware.waitUntilValid(() => { 89 | console.log("> Listening at " + uri + "\n"); 90 | // when env is testing, don't need open it 91 | if (autoOpenBrowser && process.env.NODE_ENV !== "testing") { 92 | opn(uri); 93 | } 94 | _resolve(); 95 | }); 96 | 97 | var server = app.listen(port); 98 | 99 | module.exports = { 100 | ready: readyPromise, 101 | close: () => { 102 | server.close(); 103 | } 104 | }; 105 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var config = require("../config"); 3 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 4 | 5 | exports.assetsPath = function(_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === "production" 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory; 9 | return path.posix.join(assetsSubDirectory, _path); 10 | }; 11 | 12 | exports.cssLoaders = function(options) { 13 | options = options || {}; 14 | 15 | var cssLoader = { 16 | loader: "css-loader", 17 | options: { 18 | minimize: process.env.NODE_ENV === "production", 19 | sourceMap: options.sourceMap 20 | } 21 | }; 22 | 23 | // generate loader string to be used with extract text plugin 24 | function generateLoaders(loader, loaderOptions) { 25 | var loaders = [cssLoader]; 26 | if (loader) { 27 | loaders.push({ 28 | loader: loader + "-loader", 29 | options: Object.assign({}, loaderOptions, { 30 | sourceMap: options.sourceMap 31 | }) 32 | }); 33 | } 34 | 35 | // Extract CSS when that option is specified 36 | // (which is the case during production build) 37 | if (options.extract) { 38 | return ExtractTextPlugin.extract({ 39 | use: loaders, 40 | fallback: "vue-style-loader" 41 | }); 42 | } else { 43 | return ["vue-style-loader"].concat(loaders); 44 | } 45 | } 46 | 47 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 48 | return { 49 | css: generateLoaders(), 50 | postcss: generateLoaders(), 51 | less: generateLoaders("less"), 52 | sass: generateLoaders("sass", { indentedSyntax: true }), 53 | scss: generateLoaders("sass"), 54 | stylus: generateLoaders("stylus"), 55 | styl: generateLoaders("stylus") 56 | }; 57 | }; 58 | 59 | // Generate loaders for standalone style files (outside of .vue) 60 | exports.styleLoaders = function(options) { 61 | var output = []; 62 | var loaders = exports.cssLoaders(options); 63 | for (var extension in loaders) { 64 | var loader = loaders[extension]; 65 | output.push({ 66 | test: new RegExp("\\." + extension + "$"), 67 | use: loader 68 | }); 69 | } 70 | return output; 71 | }; 72 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require("./utils"); 2 | var config = require("../config"); 3 | var isProduction = process.env.NODE_ENV === "production"; 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }) 12 | }; 13 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var utils = require("./utils"); 3 | var config = require("../config"); 4 | var vueLoaderConfig = require("./vue-loader.conf"); 5 | 6 | function resolve(dir) { 7 | return path.join(__dirname, "..", dir); 8 | } 9 | 10 | module.exports = { 11 | entry: { 12 | app: "./src/main.js" 13 | }, 14 | output: { 15 | path: config.build.assetsRoot, 16 | filename: "[name].js", 17 | publicPath: process.env.NODE_ENV === "production" 18 | ? config.build.assetsPublicPath 19 | : config.dev.assetsPublicPath 20 | }, 21 | resolve: { 22 | extensions: [".vue", ".js", ".json"], 23 | alias: { 24 | vue$: "vue/dist/vue.esm.js", 25 | "@": resolve("src") 26 | } 27 | }, 28 | module: { 29 | rules: [ 30 | { 31 | test: /\.vue$/, 32 | loader: "vue-loader", 33 | options: vueLoaderConfig 34 | }, 35 | { 36 | test: /\.js$/, 37 | loader: "babel-loader", 38 | include: [resolve("src"), resolve("test")] 39 | }, 40 | { 41 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 42 | loader: "url-loader", 43 | options: { 44 | limit: 10000, 45 | name: utils.assetsPath("img/[name].[hash:7].[ext]") 46 | } 47 | }, 48 | { 49 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 50 | loader: "url-loader", 51 | options: { 52 | limit: 10000, 53 | name: utils.assetsPath("fonts/[name].[hash:7].[ext]") 54 | } 55 | } 56 | ] 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require("./utils"); 2 | var webpack = require("webpack"); 3 | var config = require("../config"); 4 | var merge = require("webpack-merge"); 5 | var baseWebpackConfig = require("./webpack.base.conf"); 6 | var HtmlWebpackPlugin = require("html-webpack-plugin"); 7 | var FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); 8 | var swWebpackConfig = require("./webpack.sw.conf"); 9 | 10 | // add hot-reload related code to entry chunks 11 | Object.keys(baseWebpackConfig.entry).forEach(function(name) { 12 | baseWebpackConfig.entry[name] = ["./build/dev-client"].concat( 13 | baseWebpackConfig.entry[name] 14 | ); 15 | }); 16 | 17 | const webpackConfig = merge(baseWebpackConfig, { 18 | module: { 19 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 20 | }, 21 | // cheap-module-eval-source-map is faster for development 22 | devtool: "cheap-module-inline-source-map", 23 | plugins: [ 24 | new webpack.DefinePlugin({ 25 | "process.env": config.dev.env 26 | }), 27 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 28 | new webpack.HotModuleReplacementPlugin(), 29 | new webpack.NoEmitOnErrorsPlugin(), 30 | // https://github.com/ampedandwired/html-webpack-plugin 31 | new HtmlWebpackPlugin({ 32 | filename: "index.html", 33 | template: "index.html", 34 | inject: true 35 | }), 36 | new FriendlyErrorsPlugin() 37 | ] 38 | }); 39 | 40 | const swConfig = merge(swWebpackConfig, { 41 | devtool: "cheap-module-inline-source-map", 42 | plugins: [ 43 | new webpack.DefinePlugin({ 44 | "process.env": config.dev.env 45 | }), 46 | new webpack.NoEmitOnErrorsPlugin() 47 | ] 48 | }); 49 | 50 | module.exports = [webpackConfig, swConfig]; 51 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var utils = require("./utils"); 3 | var webpack = require("webpack"); 4 | var config = require("../config"); 5 | var merge = require("webpack-merge"); 6 | var baseWebpackConfig = require("./webpack.base.conf"); 7 | var CopyWebpackPlugin = require("copy-webpack-plugin"); 8 | var HtmlWebpackPlugin = require("html-webpack-plugin"); 9 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 10 | var OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin"); 11 | var MinifyPlugin = require("babel-minify-webpack-plugin"); 12 | var swWebpackConfig = require("./webpack.sw.conf"); 13 | 14 | var env = config.build.env; 15 | 16 | var webpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ 19 | sourceMap: config.build.productionSourceMap, 20 | extract: true 21 | }) 22 | }, 23 | devtool: config.build.productionSourceMap ? "#source-map" : false, 24 | output: { 25 | path: config.build.assetsRoot, 26 | filename: utils.assetsPath("js/[name].[chunkhash].js"), 27 | chunkFilename: utils.assetsPath("js/[id].[chunkhash].js") 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | "process.env": env 33 | }), 34 | // Let's use Minify Plugin 35 | new MinifyPlugin(), 36 | // extract css into its own file 37 | new ExtractTextPlugin({ 38 | filename: utils.assetsPath("css/[name].[contenthash].css") 39 | }), 40 | // Compress extracted CSS. We are using this plugin so that possible 41 | // duplicated CSS from different components can be deduped. 42 | new OptimizeCSSPlugin({ 43 | cssProcessorOptions: { 44 | safe: true 45 | } 46 | }), 47 | // generate dist index.html with correct asset hash for caching. 48 | // you can customize output by editing /index.html 49 | // see https://github.com/ampedandwired/html-webpack-plugin 50 | new HtmlWebpackPlugin({ 51 | filename: config.build.index, 52 | template: "index.html", 53 | inject: true, 54 | minify: { 55 | removeComments: true, 56 | collapseWhitespace: true, 57 | removeAttributeQuotes: true 58 | // more options: 59 | // https://github.com/kangax/html-minifier#options-quick-reference 60 | }, 61 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 62 | chunksSortMode: "dependency" 63 | }), 64 | // split vendor js into its own file 65 | new webpack.optimize.CommonsChunkPlugin({ 66 | name: "vendor", 67 | minChunks: function(module, count) { 68 | // any required modules inside node_modules are extracted to vendor 69 | return ( 70 | module.resource && 71 | /\.js$/.test(module.resource) && 72 | module.resource.indexOf(path.join(__dirname, "../node_modules")) === 0 73 | ); 74 | } 75 | }), 76 | // extract webpack runtime and module manifest to its own file in order to 77 | // prevent vendor hash from being updated whenever app bundle is updated 78 | new webpack.optimize.CommonsChunkPlugin({ 79 | name: "manifest", 80 | chunks: ["vendor"] 81 | }), 82 | // copy custom static assets 83 | new CopyWebpackPlugin([ 84 | { 85 | from: path.resolve(__dirname, "../static"), 86 | to: config.build.assetsSubDirectory, 87 | ignore: [".*"] 88 | } 89 | ]) 90 | ] 91 | }); 92 | 93 | if (config.build.productionGzip) { 94 | var CompressionWebpackPlugin = require("compression-webpack-plugin"); 95 | 96 | webpackConfig.plugins.push( 97 | new CompressionWebpackPlugin({ 98 | asset: "[path].gz[query]", 99 | algorithm: "gzip", 100 | test: new RegExp( 101 | "\\.(" + config.build.productionGzipExtensions.join("|") + ")$" 102 | ), 103 | threshold: 10240, 104 | minRatio: 0.8 105 | }) 106 | ); 107 | } 108 | 109 | if (config.build.bundleAnalyzerReport) { 110 | var BundleAnalyzerPlugin = require("webpack-bundle-analyzer") 111 | .BundleAnalyzerPlugin; 112 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()); 113 | } 114 | 115 | const swConfig = merge(swWebpackConfig, { 116 | plugins: [ 117 | new webpack.DefinePlugin({ 118 | "process.env": env 119 | }), 120 | new MinifyPlugin() 121 | ] 122 | }); 123 | 124 | module.exports = [webpackConfig, swConfig]; 125 | -------------------------------------------------------------------------------- /build/webpack.sw.conf.js: -------------------------------------------------------------------------------- 1 | const baseWebpackConfig = require("./webpack.base.conf"); 2 | 3 | module.exports = { 4 | entry: "./src/sw.js", 5 | target: "webworker", 6 | output: { 7 | path: baseWebpackConfig.output.path, 8 | filename: "sw.js", 9 | publicPath: baseWebpackConfig.output.publicPath 10 | }, 11 | module: baseWebpackConfig.module 12 | }; 13 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require("webpack-merge"); 2 | var prodEnv = require("./prod.env"); 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }); 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require("path"); 3 | 4 | module.exports = { 5 | build: { 6 | env: require("./prod.env"), 7 | index: path.resolve(__dirname, "../dist/index.html"), 8 | assetsRoot: path.resolve(__dirname, "../dist"), 9 | assetsSubDirectory: "static", 10 | assetsPublicPath: "/", 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ["js", "css"], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require("./dev.env"), 26 | port: 8080, 27 | autoOpenBrowser: false, 28 | assetsSubDirectory: "static", 29 | assetsPublicPath: "/", 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | }; 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | babel-time-travel 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-time-travel", 3 | "version": "1.0.0", 4 | "description": "Timetravel interface for babel transformations", 5 | "author": "Boopathi Rajaa ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "promise-worker-transferable": "^1.0.4", 14 | "vue": "^2.3.3", 15 | "vue-codemirror-lite": "^1.0.1", 16 | "vuex": "^2.3.1" 17 | }, 18 | "devDependencies": { 19 | "autoprefixer": "^7.1.1", 20 | "babel-core": "^6.22.1", 21 | "babel-loader": "^7.0.0", 22 | "babel-minify-webpack-plugin": "^0.3.1", 23 | "babel-plugin-transform-runtime": "^6.22.0", 24 | "babel-preset-env": "^1.3.2", 25 | "babel-preset-minify": "^0.4.3", 26 | "babel-preset-stage-2": "^6.22.0", 27 | "babel-register": "^6.22.0", 28 | "chalk": "^1.1.3", 29 | "connect-history-api-fallback": "^1.3.0", 30 | "copy-webpack-plugin": "^4.0.1", 31 | "css-loader": "^0.28.0", 32 | "eventsource-polyfill": "^0.9.6", 33 | "express": "^4.14.1", 34 | "extract-text-webpack-plugin": "^2.0.0", 35 | "file-loader": "^0.11.2", 36 | "friendly-errors-webpack-plugin": "^1.1.3", 37 | "html-webpack-plugin": "^2.28.0", 38 | "http-proxy-middleware": "^0.17.3", 39 | "opn": "^5.0.0", 40 | "optimize-css-assets-webpack-plugin": "^2.0.0", 41 | "ora": "^1.2.0", 42 | "rimraf": "^2.6.0", 43 | "semver": "^5.3.0", 44 | "shelljs": "^0.7.6", 45 | "sw-toolbox": "^3.6.0", 46 | "url-loader": "^0.5.8", 47 | "vue-loader": "^12.1.0", 48 | "vue-style-loader": "^3.0.1", 49 | "vue-template-compiler": "^2.3.3", 50 | "webpack": "^2.6.1", 51 | "webpack-bundle-analyzer": "^2.2.1", 52 | "webpack-dev-middleware": "^1.10.0", 53 | "webpack-hot-middleware": "^2.18.0", 54 | "webpack-merge": "^4.1.0", 55 | "worker-loader": "^0.8.0" 56 | }, 57 | "engines": { 58 | "node": ">= 4.0.0", 59 | "npm": ">= 3.0.0" 60 | }, 61 | "browserslist": [ 62 | "last 2 versions" 63 | ], 64 | "resolutions": { 65 | "webpack-sources": "1.0.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | 31 | -------------------------------------------------------------------------------- /src/components/Controls.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 49 | 50 | 66 | -------------------------------------------------------------------------------- /src/components/Editor.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 38 | -------------------------------------------------------------------------------- /src/components/Errors.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 27 | 28 | 56 | -------------------------------------------------------------------------------- /src/components/Layout.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 34 | 35 | 95 | -------------------------------------------------------------------------------- /src/components/Slider.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 47 | 48 | 88 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from "vue"; 4 | import App from "./App"; 5 | 6 | import store from "./store"; 7 | 8 | Vue.config.productionTip = false; 9 | 10 | new Vue({ 11 | el: "#app", 12 | template: "", 13 | store, 14 | data() { 15 | return { 16 | title: "Babel Time Travel" 17 | }; 18 | }, 19 | components: { App } 20 | }); 21 | 22 | store.dispatch("registerSw"); 23 | -------------------------------------------------------------------------------- /src/store/babel-worker.js: -------------------------------------------------------------------------------- 1 | import registerPromiseWorker from "promise-worker-transferable/register"; 2 | import babelPresetMinify from "babel-preset-minify"; 3 | import generate from "babel-generator"; 4 | import { str2ab, ab2str } from "./buffer-utils"; 5 | importScripts("//unpkg.com/babel-standalone@6.24.2/babel.min.js"); 6 | 7 | registerPromiseWorker(function babelTransform( 8 | { source, options = {} }, 9 | withTransferList 10 | ) { 11 | if (Array.isArray(options.presets)) { 12 | for (const [i, preset] of options.presets.entries()) { 13 | if (preset === "minify") { 14 | options.presets[i] = babelPresetMinify; 15 | } 16 | } 17 | } 18 | 19 | options.ast = false; 20 | options.code = true; 21 | 22 | const transitions = []; 23 | 24 | Object.assign(options, { 25 | wrapPluginVisitorMethod(pluginAlias, visitorType, callback) { 26 | return function(...args) { 27 | const { code } = generate(getProgramParent(args[0]).node); 28 | if ( 29 | transitions.length === 0 || 30 | transitions[transitions.length - 1].code !== code 31 | ) { 32 | transitions.push({ 33 | code, 34 | pluginAlias, 35 | visitorType, 36 | currentNode: args[0].node.type, 37 | }); 38 | } 39 | callback.call(this, ...args); 40 | }; 41 | } 42 | }); 43 | 44 | const output = Babel.transform(ab2str(source), options).code; 45 | 46 | transitions.push({ 47 | code: output, 48 | pluginAlias: "output", 49 | visitorType: "exit" 50 | }); 51 | 52 | // convert to array buffers and extract buffers 53 | const buffers = []; 54 | for (const transition of transitions) { 55 | Object.assign(transition, { 56 | code: str2ab(transition.code) 57 | }); 58 | buffers.push(transition.code); 59 | } 60 | 61 | return withTransferList({ transitions }, buffers); 62 | }); 63 | 64 | function getProgramParent(path) { 65 | let parent = path; 66 | do { 67 | if (parent.isProgram()) return parent; 68 | } while ((parent = parent.parentPath)); 69 | } 70 | -------------------------------------------------------------------------------- /src/store/buffer-utils.js: -------------------------------------------------------------------------------- 1 | // Source: https://stackoverflow.com/a/11058858 2 | export function ab2str(buf) { 3 | return String.fromCharCode.apply(null, new Uint16Array(buf)); 4 | } 5 | 6 | export function str2ab(str) { 7 | var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char 8 | var bufView = new Uint16Array(buf); 9 | for (var i = 0, strLen = str.length; i < strLen; i++) { 10 | bufView[i] = str.charCodeAt(i); 11 | } 12 | return buf; 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/store/byte-utils.js: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/babel/website/blob/master/js/repl/Utils.js 2 | 3 | const sizes = ["Bytes", "kB", "MB", "GB", "TB", "PB", "EB"]; 4 | 5 | export function prettySize(size) { 6 | const places = 1; 7 | let mysize; 8 | 9 | sizes.forEach((unit, id) => { 10 | const s = Math.pow(1024, id); 11 | let fixed; 12 | if (size >= s) { 13 | fixed = String((size / s).toFixed(places)); 14 | if (fixed.indexOf(".0") === fixed.length - 2) { 15 | fixed = fixed.slice(0, -2); 16 | } 17 | mysize = `${fixed} ${unit}`; 18 | } 19 | }); 20 | 21 | // zero handling 22 | // always prints in Bytes 23 | if (!mysize) { 24 | const unit = sizes[0]; 25 | mysize = `0 ${unit}`; 26 | } 27 | return mysize; 28 | } 29 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import PromiseWorker from "promise-worker-transferable"; 4 | import { str2ab, ab2str } from "./buffer-utils"; 5 | import { prettySize } from "./byte-utils" 6 | 7 | Vue.use(Vuex); 8 | 9 | import _babelWorker from "worker-loader!./babel-worker.js"; 10 | 11 | export const babelWorker = new PromiseWorker(_babelWorker()); 12 | 13 | function getSource(code) { 14 | return { 15 | code, 16 | pluginAlias: "source", 17 | visitorType: "enter", 18 | size: prettySize(new Blob([code], { type: "text/plain" }).size), 19 | }; 20 | } 21 | 22 | const sourcePluginAlias = "source"; 23 | const sourceVisitorType = "enter"; 24 | 25 | export default new Vuex.Store({ 26 | strict: true, 27 | state: { 28 | current: 0, 29 | transitions: [getSource("class Foo {}")], 30 | options: { 31 | presets: ["es2015", "minify"] 32 | }, 33 | error: void 0, 34 | sw: null 35 | }, 36 | getters: { 37 | availablePresets() { 38 | return ["es2015", "stage-0", "stage-1", "stage-2", "stage-3", "minify"]; 39 | } 40 | }, 41 | mutations: { 42 | updateCurrent(state, current) { 43 | if (state.transitions.length >= current) { 44 | state.current = current; 45 | } 46 | }, 47 | updateSource(state, code) { 48 | // remove the error; 49 | if (state.error) { 50 | state.error = void 0; 51 | } 52 | state.transitions[0] = getSource(code); 53 | }, 54 | updatePresets(state, presets) { 55 | state.options.presets = [...presets]; 56 | }, 57 | clearTransitions(state) { 58 | state.transitions = [state.transitions[0]]; 59 | state.current = 0; 60 | }, 61 | receiveResult(state, transitions) { 62 | state.transitions.push(...transitions); 63 | }, 64 | addError(state, error) { 65 | state.error = error; 66 | }, 67 | removeError(state) { 68 | state.error = void 0; 69 | }, 70 | setSw(state, reg) { 71 | state.sw = reg; 72 | }, 73 | removeSw(state) { 74 | state.sw = null; 75 | } 76 | }, 77 | actions: { 78 | error({ commit }, error) { 79 | commit("addError", error); 80 | setTimeout(() => { 81 | commit("removeError"); 82 | }, 5000); 83 | }, 84 | compile({ commit, state, dispatch }) { 85 | commit("clearTransitions"); 86 | 87 | const message = { 88 | source: str2ab(state.transitions[0].code), 89 | options: state.options 90 | }; 91 | return babelWorker 92 | .postMessage(message, [message.source]) 93 | .then(result => { 94 | const transitions = result.transitions.map( 95 | ({ code, pluginAlias, visitorType, currentNode, size }) => ({ 96 | code: ab2str(code), 97 | pluginAlias, 98 | visitorType, 99 | currentNode, 100 | size: prettySize(new Blob([code], { type: "text/plain" }).size) 101 | }) 102 | ); 103 | 104 | commit("receiveResult", transitions); 105 | return transitions; 106 | }) 107 | .catch(err => { 108 | dispatch("error", err.message); 109 | }); 110 | }, 111 | registerSw({ commit }) { 112 | if (navigator.serviceWorker) { 113 | navigator.serviceWorker.register("/sw.js").then(registration => { 114 | commit("setSw", registration); 115 | }); 116 | } 117 | }, 118 | clearCaches() { 119 | if (caches) { 120 | return caches 121 | .keys() 122 | .then(keyList => Promise.all(keyList.map(key => caches.delete(key)))) 123 | .then(() => console.log("All caches removed")) 124 | .catch(err => console.error(err)); 125 | } 126 | }, 127 | unregisterSw({ state, commit }) { 128 | if (state.sw) { 129 | return state.sw.unregister().then(isUnregistered => { 130 | if (isUnregistered) { 131 | console.log("ServiceWorker unregistered"); 132 | commit("removeSw"); 133 | } else { 134 | console.error(new Error("UnRegistering ServiceWorker failed")); 135 | } 136 | }); 137 | } 138 | } 139 | } 140 | }); 141 | -------------------------------------------------------------------------------- /src/sw.js: -------------------------------------------------------------------------------- 1 | import toolbox from "sw-toolbox"; 2 | 3 | const VERSION = 1; 4 | 5 | toolbox.options.cache.name = "Babel-Time-Travel-" + VERSION; 6 | toolbox.options.cache.maxEntries = 10; 7 | 8 | // delete items older than a day 9 | toolbox.options.cache.maxAgeSeconds = 60 * 60 * 24; 10 | 11 | toolbox.router.get("/(.*)", toolbox.cacheFirst, { 12 | origin: "https://unpkg.com/" 13 | }); 14 | toolbox.router.get("/(.*)", toolbox.cacheFirst, { 15 | origin: "https://cdnjs.cloudflare.com/" 16 | }); 17 | 18 | toolbox.router.get("/*.js", toolbox.fastest); 19 | toolbox.router.get("/*.css", toolbox.fastest); 20 | toolbox.router.get("/", toolbox.networkFirst); 21 | 22 | toolbox.router.default = toolbox.networkOnly; 23 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babel/babel-time-travel/bea3a0676814f0ec5e05935c13601dad5ec0d171/static/.gitkeep --------------------------------------------------------------------------------