Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

ES6 Import & Export

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

If you watched episode 2 of our JavaScript series, then you know that ECMAScript is the official name of the JavaScript language standard and that ECMAScript version 6 - or ES6 - introduced the idea of modules. Modules are what we've been taking advantage of this entire tutorial: exporting and requiring values from different files.

But... surprise! In ECMAScript, the require() function does not exist. Whaaaat?! The require() statement was basically invented by Node, back before ES6: Node needed a way to require files, so they invented their own way. Later, ECMAScript decided to make the idea of modules part of the standard language. But when they did, they used a different keyword than require! Yep, there are two valid syntaxes for working with modules! But... it's not a big deal: they work exactly the same, except that the official syntax has one small advantage.

Hello import & export

Let's use the official module syntax. Instead of saying const Helper = require(), say import Helper from:

... lines 1 - 2
import Helper from './RepLogHelper';
... lines 4 - 215

It's that simple! And it doesn't change anything. In RepLogHelper, we also need to change our export to use the new syntax. Instead of module.exports = Helper, use export default Helper:

... lines 1 - 33
export default Helper;

We'll talk about what the default part means later. But for now, it's always export default and then what you want to export.

You can mix the two syntaxes - require and import - to a certain point, but you may run into some problems. Your best bet is to pick your favorite - mine is import and export - and use it everywhere. So let's update everything: import $ from 'jquery', import swal from 'sweetalert2' and import Routing from './Routing':

... lines 1 - 2
import Helper from './RepLogHelper';
import $ from 'jquery';
import swal from 'sweetalert2';
import Routing from './Routing';
... lines 7 - 215

At the bottom, use export default RepLogApp:

... lines 1 - 213
export default RepLogApp;

Cool! RepLogHelper is already ok, and in Routing.js, change this to: export default window.Routing:

... lines 1 - 4
export default window.Routing;

Keep going for the 3 entry files: import $ from 'jquery':

... lines 1 - 2
import $ from 'jquery';
... lines 4 - 12

If you don't need a return value, it's even easier: just import 'bootstrap'. Repeat that for the CSS files:

... lines 1 - 2
import $ from 'jquery';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';
import '../css/main.scss';
... lines 8 - 12

In login.js, import jQuery again, then import the CSS file:

... lines 1 - 2
import $ from 'jquery';
import '../css/login.css';
... lines 5 - 24

And one more time in rep_log.js: import jQuery and import RepLogApp:

... lines 1 - 2
import $ from 'jquery';
import RepLogApp from './Components/RepLogApp';
... lines 5 - 10

And... assuming I didn't mess anything up, our build should still be happy! Check out the terminal: yes! No errors. Move over to your browser and check it! Looks great!

Importing Named Modules

And... yea! That's it! Just two nearly-identical syntaxes... because... more is better?! The biggest reason I want you to know about import and export is so that you know what it means when you see it in code or documentation.

But, there is one small advantage to import and export, and it relates to this default keyword:

... lines 1 - 213
export default RepLogApp;

Usually, you'll want to export just one value from a module. In that case, you say export default and then you receive this value when using import.

But... technically... you can export multiple things from a module, as long as you give each of them a name. For example, instead of export default Helper, we could export an object with a Helper key and a foo key:

import {Helper, foo} from './RepLogHelper';

Then, the import has a slightly different syntax where you say explicitly which of those keys you want to import.

I don't usually do this in my code, but there is one case where it can be helpful. Imagine you're using a huge external library - like lodash - which is really just a collection of independent functions. If that library exports its values correctly, you could import just the functions you need, instead of importing the entire exported value:

import isEqual from 'lodash.isequal';

Then, at least in theory, thanks to a feature called "tree shaking", Webpack would realize that you're only using a few parts of that library, and only include those in the final, compiled file. In reality, this still seems a bit buggy: the unused code doesn't always get removed. But, the point is this: import and export have a subtle advantage and are the ECMAScript standard. So, use them!

Ok, it's time to find out how we can create a crazy-fast production build!

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": "^7.2.0",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^1.6", // 1.8.1
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
        "doctrine/doctrine-fixtures-bundle": "~3.0", // 3.0.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.1
        "doctrine/orm": "^2.5", // v2.7.2
        "friendsofsymfony/jsrouting-bundle": "^2.2", // 2.2.0
        "friendsofsymfony/user-bundle": "dev-master", // dev-master
        "sensio/framework-extra-bundle": "^5.1", // v5.1.5
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.4
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/form": "^4.0", // v4.0.4
        "symfony/framework-bundle": "^4.0", // v4.0.4
        "symfony/lts": "^4@dev", // dev-master
        "symfony/monolog-bundle": "^3.1", // v3.1.2
        "symfony/polyfill-apcu": "^1.0", // v1.7.0
        "symfony/serializer-pack": "^1.0", // v1.0.1
        "symfony/swiftmailer-bundle": "^3.1", // v3.1.6
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/validator": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0", // v4.0.4
        "twig/twig": "2.10.*" // v2.10.0
    "require-dev": {
        "symfony/debug-pack": "^1.0", // v1.0.4
        "symfony/dotenv": "^4.0", // v4.0.4
        "symfony/phpunit-bridge": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0" // v4.0.4

What JavaScript libraries does this tutorial use?

// package.json
    "devDependencies": {
        "@symfony/webpack-encore": "^0.19.0", // 0.19.0
        "bootstrap": "3", // 3.3.7
        "copy-webpack-plugin": "^4.4.1", // 4.4.1
        "font-awesome": "4", // 4.7.0
        "jquery": "^3.3.1", // 3.3.1
        "node-sass": "^4.7.2", // 4.7.2
        "sass-loader": "^6.0.6", // 6.0.6
        "sweetalert2": "^7.11.0", // 7.11.0
        "webpack-notifier": "^1.5.1" // 1.5.1