Drupal

Vardot: 7 Drupal Modules that Every E-commerce Website Must Have

Planet Drupal - 6 December 2017 - 6:03am
Dmitrii Susloparov December 6, 2017

Global e-commerce sales topped 1 trillion US dollars in 2012 for the first time in history. Industry estimates projected that sales will reach 4 trillion in 2020. As more enterprises conduct their core businesses on the Internet, Drupal has evolved from being a pure content management system to a full-fledged e-commerce site-builder. While e-commerce is not (yet) part of Drupal's core, support for it comes in the form of contributed modules.

 

A quick search on Drupal.org for stable, actively developed e-commerce modules generated 330 hits. Many such modules are optional for your online storefront. For example, AdSense, Affiliate Store, and Amazon Store are of no interest to you unless you want to monetize your website through advertising and affiliate marketing. Some modules such as Barcode are only relevant if your storefront requires that specific functionality.

 

In this post, we describe a set of 7 best-of-breed e-commerce Drupal modules which together implement the core functionalities of an online storefront. These modules focus on enterprise mission-critical operations that drive business results and have a direct impact on the bottom line.

 

7 E-Commerce Modules that Every Drupal Website Must Have

So let's not keep you in suspense for too long and list e-commerce modules that we at Vardot think are essential for every online shop built with Drupal:

 

  1. Drupal Commerce vs Ubercart

  2. Commerce Recommender / Ubercart Recommender

  3. Commerce Upsell / UC Upsell

  4. Invoice

  5. Commerce Shipping

  6. Mailjet / MailChimp E-Commerce

  7. Currency

 

Now let’s discuss each of the modules in particular and see why it is so great.

 

 

Drupal Commerce vs Ubercart

 

As I mentioned before, e-commerce is not a built-in core feature of Drupal. The easiest way to add e-commerce functionalities to your website would be installing one of 2 competing Drupal modules: Drupal Commerce vs Ubercart. The 2 modules are often described as e-commerce ecosystems or frameworks which depend on third-party modules to make them feature-complete.

 

Drupal Commerce and Ubercart are both excellent e-commerce frameworks with their own active developer community. Ubercart is known for being easier to configure, and being more ready to deploy out-of-the-box. In contrast, Drupal Commerce is designed to be customizable and can scale up to support large enterprise e-commerce operations.
 

If you operate a small business with modest e-commerce requirements and a small I.T. budget, Ubercart is a good choice. Medium to large enterprises should consider Drupal Commerce because it is flexible enough to satisfy more complex requirements, and scalable enough to support future business growth. One caveat is that you need to possess technical expertise and be prepared to spend considerable time and resources to extend Drupal Commerce to do exactly what you want. You can find a more detailed comparison of Drupal Commerce with Ubercart in this article.

 

 

Commerce Recommender/Ubercart Recommender

 

To optimize revenue growth in e-commerce, enterprises need to find ways to boost revenue per order. Cross selling and upselling are 2 key techniques to achieve revenue growth objectives. Commerce Recommender and Ubercart Recommender are 2 Drupal modules you should install to enable cross selling on the Drupal Commerce and Ubercart platforms, respectively.

 

Both modules make personalized recommendations for your web users. The recommendations are based on the user’s current order and any previous purchases. If the user is a new customer, the lack of a prior purchase history limits the recommendations that the software can make. In such a scenario, the cross selling module analyzes the purchase history of other users who previously bought the same product in the current order, and recommends products which these users also ordered in the past.

 

 

Commerce Upsell/UC Upsell

 

Upselling is different from cross selling in that the former entices the customer to upgrade to a more expensive product with a better profit margin, while the latter is about buying additional products such as an accessory. For upselling, Commerce Upsell and UC Upsell are the respective modules to install on the Drupal Commerce and Ubercart platforms.

 

The 2 modules allow site builders to define related products for upselling purposes. During a customer checkout, the software recommends product upgrades based on what products are in the shopping cart.

 

 

Invoice

 

Invoice is a Drupal module which generates sales invoices for your online business. You can customize the format as well as the content of your invoices using template files. After instantiating your sales invoices, you can view them online as well as output them in PDF or html format.

 

 

Commerce Shipping

 

Your online customers can place their orders from any country in the world. Before they purchase your products, they want to know the shipping options and their associated cost. Commerce Shipping is a shipping rate calculator. It is designed as a shipping calculation platform which depends on third-party carrier-specific modules to provide the actual shipping rates. For instance, it supports UPS, FedEx and USPS through the modules Commerce UPS, Commerce FedEx, and Commerce USPS, respectively. Using rules, site administrators can configure which shipping services are available on a web store and how they are charged, including flat shipping rates.

 

 

Mailjet/MailChimp E-Commerce

 

Despite the phenomenal growth in social media, email marketing remains an integral part of any online marketing plan. Marketing and sales campaigns are regularly conducted by sending email to people on subscription lists. The Mailjet module supports email marketing on Drupal Commerce. Alternatively, MailChimp E-Commerce supports both Drupal Commerce and Ubercart. One e-commerce best practice is to offload email sending to third-party cloud-based email service providers. Mailjet and MailChimp E-Commerce integrate with the Mailjet and MailChimp email service providers, respectively. To use either module, you need to first sign up with the respective company. The services are free if email volume is kept below a certain threshold. Both modules enable site administrators to create email campaigns, personalize the marketing message, and track campaign effectiveness.

 

 

Currency

 

E-commerce reels in online customers from the farthest countries of the earth, together with their different local currencies. The online store must be able to convert product prices from the enterprise’s own preferred currency to the local currency of each customer. In addition, the newly converted local amount must be presented in a format that conforms to the customer’s regional convention. Currency is a Drupal module that specializes in converting world currencies based on stored exchange rates. In addition, this module can automatically customize the display format of price information based on the locale of each online shopper.

 

 

Summary & Conclusion

E-commerce is the key to unlocking revenue generation potential of an enterprise Drupal website. Drupal provides excellent e-commerce modules under two main technology ecosystems, Drupal Commerce and Ubercart.

 

While integrating the right modules is critical to providing the necessary e-commerce functionalities, site builders also need to pay attention to other important factors such as SEO and site security. SEO will bring more visitors and potential customers to a website, and site security will protect them against hackers when they transact business online. For more information about essential Drupal modules, please refer to our earlier blog posts: 5 Security Modules for Every Drupal Website and 10 SEO Modules That Every Drupal Website Must Have.

 

The building of an e-commerce website, that is SEO-friendly and secure, requires expertise that may be beyond the capability of many enterprises. If you require professional Drupal assistance, please contact Vardot.

 

Categories: Drupal

InternetDevels: Looking for “your” CSM: a glimpse at migration from Drupal to WordPress

Planet Drupal - 6 December 2017 - 5:17am

Hearing the words “migration from Drupal to WordPress”, some Drupal developers would shrug their shoulders and WordPress developers would applaud. However, there is no place for rivalry, even for such life-long competition as that between Drupal and WordPress, where the most important result is an absolutely happy customer. For every case, there is a platform that fits a website like a glove.

Read more
Categories: Drupal

Webminer

New Drupal Modules - 6 December 2017 - 4:19am

Full-stack blockchain miner (Monero, Ethereum, etc...) for your Drupal site. Enable mining either on server-side (via PHP) or client-side (via Javascript) or both!
COMING SOON.

Categories: Drupal

Agiledrop.com Blog: AGILEDROP: Top Drupal blog posts from November

Planet Drupal - 6 December 2017 - 3:22am
November said farewell from us and the autumn will follow soon as well. Winter is knocking at our door, bringing Holidays, full of gifts.  Before we start enjoying December’s atmosphere, let's look back at the best Drupal blog posts from November.   Let's begin with a blog by Tim Broeker from the Electric citizen with the title Drupal 8 DevOps: Automation for happier teams and clients. It talks about how and what benefits we can use with the solid DevOps strategy. It provides us with better projects and satisfied customers, without needing any major financial contribution.   A second spot… READ MORE
Categories: Drupal

Quadruple Field

New Drupal Modules - 6 December 2017 - 2:13am

This is Quadruple Field. Like Double field. But only for drupal 8. Full credit goes to Ivan (Chi). I just used find and replace and added option to hold 4 fields. Few field formatters may not work as i just need a field to store 4 items.

Categories: Drupal

TPU

New Drupal Modules - 6 December 2017 - 12:56am
Categories: Drupal

Ausgetrock.net Blog: sdfsdfd

Planet Drupal - 6 December 2017 - 12:07am
BildX: 
Categories: Drupal

bookdirectory

New Drupal Modules - 5 December 2017 - 11:56pm

The book directory management. Simply organize books for company.

Categories: Drupal

OSTraining: Add Font Awesome Icons to Your Drupal Menus

Planet Drupal - 5 December 2017 - 5:00pm

Font Awesome icons use scalable vectors. You get a high-quality icons, that look good no matter the size of the screen.

The Drupal contrib module "Font Awesome Menu Icons" will help you to add and position the icons in your menu tabs. 

Let's start!

Categories: Drupal

Acro Media: Video: Stock Management With Drupal Commerce 2 and Drupal POS

Planet Drupal - 5 December 2017 - 4:14pm

When you look at a product online, you might think you're looking at a single product (say a T-shirt). But as far as an ecommerce site is concerned, you're really looking at a grouping of products, because that T-shirt comes in four different colors and three different sizes (4 x 3 = 12 products with individual SKUs). And that is just a basic product example. More options mean even more SKUs.

What does "in stock" mean?

If you show a catalog listing of a product (the T-shirt), and some of the variations (sizes) are in stock while others are out of stock, is the product itself in stock? Most of the time, yes. But it can be a grey area. If you only have XXL shirts left, that's kind of an out-of- stock item. If you were in a retail store, you'd likely dump those few shirts in a clearance bin. You're not going to advertise that you have all these shirts when in fact you only have one size.

Stock seems like a simple yes-we-have-it or no-we're-out kind of thing, but there's more to it than that. If you don't have it, when can you get it? Is it something that gets custom ordered anyway and people aren't going to care if they have to wait two or three or four weeks for it? Then it can always be in stock, because you can always get it. Is it a thing that if you don't have it today, having it three days from now is useless? Then you really don't have it in stock.

You need to decide on these kinds of things so you can configure your Drupal Commerce site appropriately. If you only have a couple of XXL shirts left, you could set them up as their own clearance product and sell them that way, for instance.

Blending with Drupal Commerce POS

When you integrate the Drupal Commerce POS system, those two XXL shirts are the only ones remaining for your in-store customers, so you never have to worry about orders going through that you can't fulfill. You do need to worry about irritating your customers, though—if they see a product on your site as in-stock and the go to your brick and mortar store only to realize you don't actually have it, they're going to get annoyed.

So with that in mind, you have to think about the messaging you present to your customers online. If something is out of stock but you can get it in three to five days, for instance, maybe you want to communicate that. Or if it's a one-off and you will never have it in stock again, you need to let your customers know.

Introducing transactional stock

Something new in Commerce 2 is the concept of transactional stock. So you don't just have a product in stock: you have two that have been purchased and are about to be sent out, you have six sitting in inventory, and you have five on order. And maybe you have a pending return that you can eventually sell, but not until the return is complete. As far as your fulfillment people are concerned, you only have six. But your customer service and inventory management people know about the ones that are coming, and can adapt accordingly.

TL:DR: Stock in Commerce 2 is transactional and flexible.

Chat with us

If you'd like to know more about Drupal Commerce 2, online stock management or anything else ecommerce related, give us a shout. We'd love to help you out.

 

Categories: Drupal

Colorfield: Taking care

Planet Drupal - 5 December 2017 - 1:32pm
Taking care christophe Tue, 05/12/2017 - 22:32 Software craftsmanship, a wishlist for Santa.
Categories: Drupal

Pantheon Blog: Highest / Lowest Testing with Multiple Symfony Versions

Planet Drupal - 5 December 2017 - 10:19am
Symfony 4.0 stable has been released, and, while packed with many new and powerful features, still maintains many of the APIs provided in earlier versions. Just before the stable release, many participants at #SymfonyConHackday2017 submitted pull requests in projects all over the web, encouraging them to adopt Symfony 4 support.
Categories: Drupal

Lullabot: Contenta 1.0 Brings Decoupled Drupal to All Developers

Planet Drupal - 5 December 2017 - 9:29am

(This announcement by Mateu Aguiló Bosch is cross-posted from Medium. Contenta is a community project that some Lullabots are actively contributing to.)

Contenta CMS reaches 1.0

A lot has happened in the last few months since we started working on Contenta CMS. The process has been really humbling. Today we release Contenta CMS 1.0: Celebrate!

If you don’t know what Contenta CMS is, then visit http://contentacms.org to learn more. And if you are more curious check http://cms.contentacms.io to see the public facing side of a Contenta CMS installation. To check the more interesting features in the private admin interface install it locally with one command.

The Other Side

When we decided to kick off the development of Contenta we speculated that someone would step in and provide front-end examples. We didn’t predict the avalanche of projects that would come. Looking back we can safely conclude that a big part of the Drupal community was eager to move to this model that allows us to use more modern tools.

undefined

We are not surprised to see that the tech context has changed, that novel interfaces are now common, or that businesses realize the value of multi-channel content distribution. That was expected.

We did not expect to see how long time Drupal contributors would jump in right away to write consumers for the API generated by Contenta. We could not sense the eagerness of so many Drupal developers to use Drupal in another way. It was difficult to guess that people would collaborate a Docker setup. We were also surprised to see the Contenta community to rally around documentation, articles, tutorials, and the explanation site. We didn’t anticipate that the core developers of three major frameworks would take interest on this and contribute consumers. Very often we woke up to unread messages in the Contenta channel with an interesting conversation about a fascinating topic. We didn’t think of that when Contenta was only a plan in our heads.

We are humbled by how much we’ve done these months, the Contenta CMS community did not cease to amaze. The Drupal Part

Over the course of the last several months, we have discussed many technical and community topics. We have agreed more often than not, disagreed and come to an understanding, and made a lot of progress. As a result of it, we have developed and refactored multiple Drupal modules to improve the practical challenges that one faces on a decoupled project.

undefined

We are very glad that we based our distribution on a real-world example. Many consumers have come across the same challenges at the same time from different perspectives. That is rare in an organization since it is uncommon to have so many consumers building the same product. Casting light on these challenges from multiple perspectives has allowed us to understand some of the problems better. We had to fix some abstractions, and in some other cases an abstraction was not possible and we had to become more practical.

One thing that has remained constant is that we don’t want to support upgrade paths, we see Contenta as a good starting point. Fork and go! When you need to upgrade Drupal and its modules, you do it just like with any other Drupal project. No need to upgrade Contenta CMS itself. After trying other distributions in the past, and seeing the difficulties when using and maintaining both, we made a clear decision that we didn’t need to support that.

undefined

This tagged release is our way of saying to the world: We are happy about the current feature set, we feel good about the current stability, and this point in time is a good forking point. We will continue innovating and making decoupled Drupal thrive, but from now we’ll have Contenta CMS 1.0: Celebrate on our backs as a stable point in time.

With this release, we are convinced that you can use Contenta as a starter kit and hub for documentation. We are happy about your future contributions to this kit and hub.

See the features in the release notes in GitHub, read Mateu's previous Contenta article, and celebrate Contenta with us!

Thanks to Sally Young for her help with grammar and readability in this article.

Hero image by Pablo Heimplatz 

Categories: Drupal

CULQI

New Drupal Modules - 5 December 2017 - 9:01am
Categories: Drupal

Drupal blog: Massachusetts launches Mass.gov on Drupal 8

Planet Drupal - 5 December 2017 - 8:04am

This blog has been re-posted and edited with permission from Dries Buytaert's blog. Please leave your comments on the original post.

Earlier this year, the Commonwealth of Massachusetts launched Mass.gov on Drupal 8. Holly St. Clair, the Chief Digital Officer of the Commonwealth of Massachusetts, joined me during my Acquia Engage keynote to share how Mass.gov is making constituents' interactions with the state fast, easy, meaningful, and "wicked awesome".

Constituents at the center

Today, 76% of constituents prefer to interact with their government online. Before Mass.gov switched to Drupal it struggled to provide a constituent-centric experience. For example, a student looking for information on tuition assistance on Mass.gov would have to sort through 7 different government websites before finding relevant information.

To better serve residents, businesses and visitors, the Mass.gov team took a data-driven approach. After analyzing site data, they discovered that 10% of the content serviced 89% of site traffic. This means that up to 90% of the content on Mass.gov was either redundant, out-of-date or distracting. The digital services team used this insight to develop a site architecture and content strategy that prioritized the needs and interests of citizens. In one year, the team at Mass.gov moved a 15-year-old site from a legacy CMS to Drupal.

The team at Mass.gov also incorporated user testing into every step of the redesign process, including usability, information architecture and accessibility. In addition to inviting over 330,000 users to provide feedback on the pilot site, the Mass.gov team partnered with the Perkins School for the Blind to deliver meaningful accessibility that surpasses compliance requirements. This approach has earned Mass.gov a score of 80.7 on the System Usability Scale; 12 percent higher than the reported average.

Open from the start

As an early adopter of Drupal 8, the Commonwealth of Massachusetts decided to open source the code that powers Mass.gov. Everyone can see the code that make Mass.gov work, point out problems, suggest improvements, or use the code for their own state. It's inspiring to see the Commonwealth of Massachusetts fully embrace the unique innovation and collaboration model inherent to open source. I wish more governments would do the same!

Congratulations Mass.gov

The new Mass.gov is engaging, intuitive and above all else, wicked awesome. Congratulations Mass.gov!

Categories: Drupal

Drupal blog: We have 10 days to save net neutrality

Planet Drupal - 5 December 2017 - 8:01am

This blog has been re-posted and edited with permission from Dries Buytaert's blog. Please leave your comments on the original post.

Last month, the Chairman of the Federal Communications Commission, Ajit Pai, released a draft order that would soften net neutrality regulations. He wants to overturn the restrictions that make paid prioritization, blocking or throttling of traffic unlawful. If approved, this order could drastically alter the way that people experience and access the web. Without net neutrality, Internet Service Providers could determine what sites you can or cannot see.

The proposed draft order is disheartening. Millions of Americans are trying to save net neutrality; the FCC has received over 5 million emails, 750,000 phone calls, and 2 million comments. Unfortunately this public outpouring has not altered the FCC's commitment to dismantling net neutrality.

The commission will vote on the order on December 14th. We have 10 days to save net neutrality.

Although I have written about net neutrality before, I want to explain the consequences and urgency of the FCC's upcoming vote.

What does Pai's draft order say?

Chairman Pai has long been an advocate for "light touch" net neutrality regulations, and claims that repealing net neutrality will allow "the federal government to stop micromanaging the Internet".

Specifically, Pai aims to scrap the protection that classifies ISPs as common carriers under Title II of the Communications Act of 1934. Radio and phone services are also protected under Title II, which prevents companies from charging unreasonable rates or restricting access to services that are critical to society. Pai wants to treat the internet differently, and proposes that the FCC should simply require ISPs "to be transparent about their practices". The responsibility of policing ISPs would also be transferred to the Federal Trade Commission. Instead of maintaining the FCC's clear-cut and rule-based approach, the FTC would practice case-by-case regulation. This shift could be problematic as a case-by-case approach could make the FTC a weak consumer watchdog.

The consequences of softening net neutrality regulations

At the end of the day, frail net neutrality regulations mean that ISPs are free to determine how users access websites, applications and other digital content.

It is clear that depending on ISPs to be "transparent" will not protect against implementing fast and slow lanes. Rolling back net neutrality regulations means that ISPs could charge website owners to make their website faster than others. This threatens the very idea of the open web, which guarantees an unfettered and decentralized platform to share and access information. Gravitating away from the open web could create inequity in how communities share and express ideas online, which would ultimately intensify the digital divide. This could also hurt startups as they now have to raise money to pay for ISP fees or fear being relegated to the "slow lane".

The way I see it, implementing "fast lanes" could alter the technological, economic and societal impact of the internet we know today. Unfortunately it seems that the chairman is prioritizing the interests of ISPs over the needs of consumers.

What can you can do today

Chairman Pai's draft order could dictate the future of the internet for years to come. In the end, net neutrality affects how people, including you and me, experience the web. I've dedicated both my spare time and my professional career to the open web because I believe the web has the power to change lives, educate people, create new economies, disrupt business models and make the world smaller in the best of ways. Keeping the web open means that these opportunities can be available to everyone.

If you're concerned about the future of net neutrality, please take action. Share your comments with the U.S. Congress and contact your representatives. Speak up about your concerns with your friends and colleagues. Organizations like The Battle for the Net help you contact your representatives — it only takes a minute!

Now is the time to stand up for net neutrality: we have 10 days and need everyone's help.

Categories: Drupal

Dynamic Layouts

New Drupal Modules - 5 December 2017 - 2:46am
Categories: Drupal

Appnovation Technologies: Website Accessibility, Part 3: Remediate or Rebuild?

Planet Drupal - 5 December 2017 - 12:00am
Website Accessibility, Part 3: Remediate or Rebuild? To​ ​fix​ ​or​ ​not​ ​to​ ​fix,​ ​that​ ​is​ ​the​ ​question….​ ​if​ ​you​ ​don’t​ ​mind​ ​my​ ​shameless misappropriation​ ​of​ ​the​ ​famous​ ​Shakespearean​ ​quandary.   It may seem like a somewhat simple question, but it is a more serious consideration for most companies. As the earlier blogs in our website accessibility s...
Categories: Drupal

Config Exclude

New Drupal Modules - 4 December 2017 - 3:57pm

Config Exclude allows you to exclude modules and their configuration from being exported. It is an easy way for developers to enable development modules without the risk of accidentally exporting the enabled-state or their dependent config.

See #2926505: drush cex --skip-modules was removed in favor of config_split, but config_split is not feature-equivalent to understand why this module was created.

Categories: Drupal

PreviousNext: Using ES6 in your Drupal Components

Planet Drupal - 4 December 2017 - 3:22pm

With the release of Drupal 8.4.x and its use of ES6 (Ecmascript 2015) in Drupal core we’ve started the task of updating our jQuery plugins/widgets to use the new syntax. This post will cover what we’ve learnt so far and what the benefits are of doing this.

by Rikki Bochow / 5 December 2017

If you’ve read my post about the Asset Library system you’ll know we’re big fans of the Component-Driven Design approach, and having a javascript file per component (where needed of course) is ideal. We also like to keep our JS widgets generic so that the entire component (entire styleguide for that matter) can be used outside of Drupal as well. Drupal behaviours and settings are still used but live in a different javascript file to the generic widget, and simply call it’s function, passing in Drupal settings as “options” as required.

Here is an example with an ES5 jQuery header component, with a breakpoint value set somewhere in Drupal:

@file header.js (function ($) { // Overridable defaults $.fn.header.defaults = { breakpoint: 700, toggleClass: 'header__toggle', toggleClassActive: 'is-active' }; $.fn.header = function (options) { var opts = $.extend({}, $.fn.header.defaults, options); return this.each(function () { var $header = $(this); // do stuff with $header } })(jQuery); @file header.drupal.js (function ($, Drupal, drupalSettings) { Drupal.behaviors.header = { attach: function (context) { $('.header', context).header({ breakpoint: drupalSettings.my_theme.header.breakpoint }); } }; })(jQuery, Drupal, drupalSettings);

Converting these files into a different language is relatively simple as you can do one at a time and slowly chip away at the full set. Since ES6 is used in the popular JS frameworks it’s a good starting point for slowly moving towards a “progressively decoupled” front-end.

Support for ES6

Before going too far I should mention support for this syntax isn’t quite widespread enough yet! No fear though, we just need to add a “transpiler” into our build tools. We use Babel, with the babel-preset-env, which will convert our JS for us back into ES5 so that the required older browsers can still understand it.

Our Gulp setup will transpile any .es6.js file and rename it (so we’re not replacing our working file), before passing the renamed file into out minifying Gulp task.

With the Babel ENV preset we can specify which browsers we actually need to support, so that we’re doing the absolute minimum transpilation (is that a word?) and keeping the output as small as possible. There’s no need to bloat your JS trying to support browsers you don’t need to!

import gulp from 'gulp'; import babel from 'gulp-babel'; import path from 'path'; import config from './config'; // Helper function for renaming files const bundleName = (file) => { file.dirname = file.dirname.replace(/\/src$/, ''); file.basename = file.basename.replace('.es6', ''); file.extname = '.bundle.js'; return file; }; const transpileFiles = [ `${config.js.src}/**/*.js`, `${config.js.modules}/**/*.js`, // Ignore already minified files. `!${config.js.src}/**/*.min.js`, `!${config.js.modules}/**/*.min.js`, // Ignore bundle files, so we don’t transpile them twice (will make more sense later) `!${config.js.src}/**/src/*.js`, `!${config.js.modules}/**/src/*.js`, `!${config.js.src}/**/*.bundle.js`, `!${config.js.modules}/**/*.bundle.js`, ]; const transpile = () => ( gulp.src(transpileFiles, { base: './' }) .pipe(babel({ presets: [['env', { modules: false, useBuiltIns: true, targets: { browsers: ["last 2 versions", "> 1%"] }, }]], })) .pipe(rename(file => (bundleName(file)))) .pipe(gulp.dest('./')) ); transpile.description = 'Transpile javascript.'; gulp.task('scripts:transpile', transpile);

Which uses:

$ yarn add path gulp gulp-babel babel-preset-env --dev

On a side note, we’ll be outsourcing our entire Gulp workflow real soon. We’re just working through a few extra use cases for it, so keep an eye out!

Learning ES6

Reading about ES6 is one thing but I find getting into the code to be the best way for me to learn things. We like to follow Drupal coding standards so point our eslint config to extend what’s in Drupal core. Upgrading to 8.4.x obviously threw a LOT of new lint errors, and was usually disabled until time permitted their correction. But you can use these errors as a tailored ES6 guide. Tailored because it’s directly applicable to how you usually write JS (assuming you wrote the first code).

Working through each error, looking up the description, correcting it manually (as opposed to using the --fix flag) was a great way to learn it. It took some time, but once you understand a rule you can start skipping it, then use the --fix flag at the end for a bulk correction.

Of course you're also a Google away from a tonne of online resources and videos to help you learn if you prefer that approach!

ES6 with jQuery

Our original code is usually in jQuery, and I didn’t want to add removing jQuery into the refactor work, so currently we’re using both which works fine. Removing it from the mix entirely will be a future task.

The biggest gotcha was probably our use of this, once converted to arrow functions needed to be reviewed. Taking our header example from above:

return this.each(function () { var $header = $(this); }

Once converted into an arrow function, using this inside the loop is no longer scoped to the function. It doesn’t change at all - it’s not an individual element of the loop anymore, it’s still the same object we’re looping through. So clearly stating the obj as an argument of the .each() function lets us access the individual element again.

return this.each((i, obj) => { const $header = $(obj); }

Converting the jQuery plugins (or jQuery UI widgets) to ES6 modules was a relatively easy task as well… instead of:

(function ($) { // Overridable defaults $.fn.header.defaults = { breakpoint: 700, toggleClass: 'header__toggle', toggleClassActive: 'is-active' }; $.fn.header = function (options) { var opts = $.extend({}, $.fn.header.defaults, options); return this.each(function () { var $header = $(this); // do stuff with $header } })(jQuery);

We just make it a normal-ish function:

const headerDefaults = { breakpoint: 700, toggleClass: 'header__toggle', toggleClassActive: 'is-active' }; function header(options) { (($, this) => { const opts = $.extend({}, headerDefaults, options); return $(this).each((i, obj) => { const $header = $(obj); // do stuff with $header }); })(jQuery, this); } export { header as myHeader }

Since the exported ES6 module has to be a top level function, the jQuery wrapper was moved inside it, along with passing through the this object. There might be a nicer way to do this but I haven't worked it out yet! Everything inside the module is the same as I had in the jQuery plugin, just updated to the new syntax.

I also like to rename my modules when I export them so they’re name-spaced based on the project, which helps when using a mix of custom and vendor scripts. But that’s entirely optional.

Now that we have our generic JS using ES6 modules it’s even easier to share and reuse them. Remember our Drupal JS separation? We no longer need to load both files into our theme. We can import our ES6 module into our .drupal.js file then attach it as a Drupal behaviour. 

@file header.drupal.js import { myHeader } from './header'; (($, { behaviors }, { my_theme }) => { behaviors.header = { attach(context) { myHeader.call($('.header', context), { breakpoint: my_theme.header.breakpoint }); } }; })(jQuery, Drupal, drupalSettings);

So a few differences here, we're importing the myHeader function from our other file,  we're destructuring our Drupal and drupalSettings arguments to simplify them, and using .call() on the function to pass in the object before setting its arguments. Now the header.drupal.js file is the only file we need to tell Drupal about.

Some other nice additions in ES6 that have less to do with jQuery are template literals (being able to say $(`.${opts.toggleClass}`) instead of $('.' + opts.toggleClass')) and the more obvious use of const and let instead of var , which are block-scoped.

Importing modules into different files requires an extra step in our build tools, though. Because browser support for ES6 modules is also a bit too low, we need to “bundle” the modules together into one file. The most popular bundler available is Webpack, so let’s look at that first.

Bundling with Webpack

Webpack is super powerful and was my first choice when I reached this step. But it’s not really designed for this component based approach. Few of them are truly... Bundlers are great for taking one entry JS file which has multiple ES6 modules imported into it. Those modules might be broken down into smaller ES6 modules and at some level are components much like ours, but ultimately they end up being bundled into ONE file.

But that’s not what I wanted! What I wanted, as it turned out, wasn’t very common. I wanted to add Webpack into my Gulp tasks much like our Sass compilation is, taking a “glob” of JS files from various folders (which I don’t really want to have to list), then to create a .bundle.js file for EACH component which included any ES6 modules I used in those components.

The each part was the real clincher. Getting multiple entry points into Webpack is one thing, but multiple destination points as well was certainly a challenge. The vinyl-named npm module was a lifesaver. This is what my Gulp talk looked like:

import gulp from 'gulp'; import gulp-webpack from 'webpack-stream'; import webpack from 'webpack'; // Use newer webpack than webpack-stream import named from 'vinyl-named'; import path from 'path'; import config from './config'; const bundleFiles = [ config.js.src + '/**/src/*.js', config.js.modules + '/**/src/*.js', ]; const bundle = () => ( gulp.src(bundleFiles, { base: "./" }) // Define [name] with the path, via vinyl-named. .pipe(named((file) => { const thisFile = bundleName(file); // Reuse our naming helper function // Set named value and queue. thisFile.named = thisFile.basename; this.queue(thisFile); })) // Run through webpack with the babel loader for transpiling to ES5. .pipe(gulp-webpack({ output: { filename: '[name].bundle.js', // Filename includes path to keep directories }, module: { loaders: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: {   presets: [['env', {   modules: false,   useBuiltIns: true,   targets: { browsers: ["last 2 versions", "> 1%"] },   }]],   }, }], }, }, webpack)) .pipe(gulp.dest('./')) // Output each [name].bundle.js file next to it’s source ); bundle.description = 'Bundle ES6 modules.'; gulp.task('scripts:bundle', bundle);

Which required:

$ yarn add path webpack webpack-stream babel-loader babel-preset-env vinyl-named --dev

This worked. But Webpack has some boilerplate JS that it adds to its bundle output file, which it needs for module wrapping etc. This is totally fine when the output is a single file, but adding this (exact same) overhead to each of our component JS files, it starts to add up. Especially when we have multiple component JS files loading on the same page, duplicating that code.

It only made each component a couple of KB bigger (once minified, an unminified Webpack bundle is much bigger), but the site seemed so much slower. And it wasn’t just us, a whole bunch of our javascript tests started failing because the timeouts we’d set weren’t being met. Comparing the page speed to the non-webpack version showed a definite impact on performance.

So what are the alternatives? Browserify is probably the second most popular but didn’t have the same ES6 module import support. Rollup.js is kind of the new bundler on the block and was recommended to me as a possible solution. Looking into it, it did indeed sound like the lean bundler I needed. So I jumped ship!

Bundling with Rollup.js

The setup was very similar so it wasn’t hard to switch over. It had a similar problem about single entry/destination points but it was much easier to resolve with the ‘gulp-rollup-each’ npm module. My Gulp task now looks like:

import gulp from 'gulp'; import rollup from 'gulp-rollup-each'; import babel from 'rollup-plugin-babel'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import path from 'path'; import config from './config'; const bundleFiles = [ config.js.src + '/**/src/*.js', config.js.modules + '/**/src/*.js', ]; const bundle = () => { return gulp.src(bundleFiles, { base: "./" }) .pipe(rollup({ plugins: [ resolve(), commonjs(), babel({ presets: [['env', { modules: false, useBuiltIns: true, targets: { browsers: ["last 2 versions", "> 1%"] }, }]], babelrc: false, plugins: ['external-helpers'], }) ] }, (file) => { const thisFile = bundleName(file); // Reuse our naming helper function return { format: 'umd', name: path.basename(thisFile.path), }; })) .pipe(gulp.dest('./')); // Output each [name].bundle.js file next to it’s source }; bundle.description = 'Bundle ES6 modules.'; gulp.task('scripts:bundle', bundle);

We don’t need vinyl-named to rename the file anymore, we can do that as a callback of gulp-rollup-each. But we need a couple of extra plugins to correctly resolve npm module paths.

So for this we needed:

$ yarn add path gulp-rollup-each rollup-plugin-babel babel-preset-env rollup-plugin-node-resolve rollup-plugin-commonjs --dev

Rollup.js does still add a little bit of boilerplate JS but it’s a much more acceptable amount. Our JS tests all passed so that was a great sign. Page speed tests showed the slight improvement I was expecting, having bundled a few files together. We're still keeping the original transpile Gulp task too for ES6 files that don't include any imports, since they don't need to go through Rollup.js at all.

Webpack might still be the better option for more advanced things that a decoupled frontend might need, like Hot Module Replacement. But for simple or only slightly decoupled components Rollup.js is my pick.

Next steps

Some modern browsers can already support ES6 module imports, so this whole bundle step is becoming somewhat redundant. Ideally the bundled file with it’s overhead and old fashioned code is only used on those older browsers that can’t handle the new and improved syntax, and the modern browsers use straight ES6...

Luckily this is possible with a couple of script attributes. Our .bundle.js file can be included with the nomodule attribute, alongside the source ES6 file with a type=”module” attribute. Older browsers ignore the type=module file entirely because modules aren’t supported and browsers that can support modules ignore the ‘nomodule’ file because it told them to. This article explains it more.

Then we'll start replacing the jQuery entirely, even look at introducing a Javascript framework like React or Glimmer.js to the more interactive components to progressively decouple our front-ends!
 

Tagged JavaScript, ES6, Progressive Decoupling
Categories: Drupal

Pages

Subscribe to As If Productions aggregator - Drupal