ES6 Imports for ToDoMVC
ES6 Imports for ToDoMVC¶
As we saw in ES6 Imports with Babel, Babel is a transpiler that opens
the door to Pythonic JS. Let’s switch our ToDoMVC codebase over to use
a tiny part: ES6 Modules and imports. Along the way, we’ll refactor our
todo.js
code a bit.
Steps¶
Install dependencies:
npm install babel-preset-es2015 babel-loader --save-dev
Our
webpack.config.js
needs to be taught to transpile code using Babel when Webpack does its bundling:module.exports = { context: __dirname + '/app', entry: './app.js', module: { loaders: [ { test: /\.js$/, loader: 'babel-loader' } ] }, devtool: 'source-map' };
Webpack’s use of Babel requires a
.babelrc
configuration file:{ "presets": ["es2015"] }
Our
.eslintrc
file needs to be told to lint using ES6 features:{ "rules": { "strict": 0, "quotes": [ 1, "single" ] }, "ecmaFeatures": { "modules": true }, "env": { "browser": true, "jquery": true, "es6": true } }
The tooling is setup, let’s change
app/todo.js
to use ES6 imports and export a function. Let’s also re-organize the code to get rid of the$(document).ready
top-level handler:import $ from 'jquery'; import tmpl from './tmpl'; export default function () { var newName = $('#newName'), todoList = $('#todoList'), template = tmpl('list_todos'); var todos; function refreshToDos () { /* Fetch the list of todos and re-draw the listing */ $.get('http://localhost:5000/api/todo', function (data) { todos = data['objects']; todoList.find('ul') .replaceWith(template({todos: todos})); }); } // Create a new to do newName.change(function () { var payload = JSON.stringify({name: newName.val()}); $.post('http://localhost:5000/api/todo', payload, function () { refreshToDos(); newName.val(''); }) }); // Edit a to do todoList.on('click', '.edit', function () { // Toggle the <input> for this todo todoList.find('li').removeAttr('editing'); var li = $(this).closest('li').first().attr('editing', '1'); }); todoList.on('change', 'input', function () { // When the revealed-input changes, update using PATCH var todoId = $(this).closest('li')[0].id, data = JSON.stringify({name: $(this).val()}); $.ajax({url: 'http://localhost:5000/api/todo/' + todoId, type: 'PATCH', data: data}) .done(function () { refreshToDos(); }); }); // Delete an existing to do todoList.on('click', '.delete', function () { var todoId = $(this).closest('li')[0].id; $.ajax({url: 'http://localhost:5000/api/todo/' + todoId, type: 'DELETE'}) .done(function () { refreshToDos(); }); }); // On startup, go fetch the list of todos and re-draw refreshToDos(); };
app/tmpl.js
now exports itstmpl
function via an ES6 module default:// John Resig jQuery Microtemplating /*eslint-disable */ export default function tmpl (str, data) { // Figure out if we're getting a template, or if we need to // load the template - and be sure to cache the result. var cache = {}; var fn = !/\W/.test(str) ? cache[str] = cache[str] || tmpl(document.getElementById(str).innerHTML) : // Generate a reusable function that will serve as a template // generator (and which will be cached). new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + // Introduce the data as local variables using with(){} "with(obj){p.push('" + // Convert the template into pure JavaScript str .replace(/[\r\t\n]/g, " ") .split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r") .replace(/\t=(.*?)%>/g, "',$1,'") .split("\t").join("');") .split("%>").join("p.push('") .split("\r").join("\\'") + "');}return p.join('');"); // Provide some basic currying to the user return data ? fn(data) : fn; }; /*eslint-enable */
Finally,
app/app.js
switches to ES6 imports. Plus, it runs the function exported bytodo.js
. Note that we can name this function whatever we want on the import side:import $ from 'jquery'; import initToDo from './todo'; $(document).ready(function () { // All REST requests should send content type, and log failures $.ajaxSetup({contentType: 'application/json'}); $(document).ajaxError(function (event, jqxhr, settings, thrownError) { console.error('Ajax call failed:', settings.type, settings.url, thrownError); }); initToDo(); });
Restart/reload. Webpack needs to get the new configuration changes in
webpack.config.js
. Restart yournpm start
tool window, then reload your browser.