Problem/Motivation

Core JavasScript contribution flow had been introduced in #2809281: Use ES6 for core JavaScript development and described in Drupal core now using ES6 for javascript development. It's not clear, however, how to use es6 for contrib and custom development. The scripts from core can be used in Drupal projects with a package.json file like this one placed one or two levels above the core folder but it would be nice to be able to use the core API directly in order to to reduce redundancy.

Proposed resolution

Add an option to build and watch scripts. For instance:

yarn watch:js-dev --contrib

or

yarn watch-contrib:js-dev

The option would work exactly the same way as it does for the core js, it would just search for .es6.js files in the parent directory (web/ instead of core/).

API changes

Contrib will be able to use ES6+ if they like.

Comments

blazey created an issue. See original summary.

blazey’s picture

Issue summary: View changes
blazey’s picture

Issue summary: View changes
blazey’s picture

dawehner’s picture

+1 for the idea! Enabling contrib people to use es6 is really nice! One thing to keep in mind though is that they cannot add external packages easily yet, but I think that's fine.

I'm curious whether instead of adding --contrib/--dev or anything like that the simpler option would be a --dir option.

blazey’s picture

StatusFileSize
new433.75 KB
new21.64 KB

Thanks for sharing your opinion @dawehner. Adding the ability to import packages doesn't seem to be easy right now, however, having something like a central webpack entry point would be a huge step forward in terms of JS DX and progressive decoupling.

About the second part, --dir is definitely more versatile. Attaching a patch that adds such an option to build and watch scripts. It defaults to ./, so the core workflow remains unchanged.

Example usage for contrib / custom code:

yarn build:js --dir ../
yarn watch:js --dir ../

babel-core prior to 7.0.0-alpha.3 has a bug in plugin resolution which makes it impossible to process any files that aren't inside the directory with package.json (see Transpile outside of node_module 'root'), so babel-core update was required.

The upgrade caused minor differences in quite a few .js files, so the real changes (excluding those from artifacts) are in a separate file.

blazey’s picture

Status: Active » Needs review

The last submitted patch, 6: 2957390-6.patch, failed testing. View results

blazey’s picture

Status: Needs review » Postponed

Looks like babel 7.0.0-beta.3 causes issues in tabledrag. This is the most recent version available on npm, so we might need to wait for a full release.

dawehner’s picture

I was curious whether it is possible to see this problem in the diff.

  1. +++ b/core/misc/tabledrag.js
    @@ -4,11 +4,11 @@
    -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
    +
    +function _typeof(obj) { if (typeof Symbol === "function" && _typeof(Symbol.iterator) === "symbol") { _typeof = function (_typeof2) { function _typeof(_x) { return _typeof2.apply(this, arguments); } _typeof.toString = function () { return _typeof2.toString(); }; return _typeof; }(function (obj) { return typeof obj === "undefined" ? "undefined" : _typeof(obj); }); } else { _typeof = function (_typeof3) { function _typeof(_x2) { return _typeof3.apply(this, arguments); } _typeof.toString = function () { return _typeof3.toString(); }; return _typeof; }(function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj); }); } return _typeof(obj); }
    

    This is one of the differences which could make a difference.

  2. +++ b/core/misc/tabledrag.js
    @@ -546,21 +537,21 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
           if (y > rowY - rowHeight && y < rowY + rowHeight) {
    -        if (_this3.indentEnabled) {
    -          if (Object.keys(_this3.rowObject.group).some(function (o) {
    +        if (this.indentEnabled) {
    +          if (Object.keys(this.rowObject.group).some(function (o) {
                 return _this3.rowObject.group[o] === row;
               })) {
    ...
    -        } else if (row === _this3.rowObject.element) {
    +        } else if (row === this.rowObject.element) {
                 return {
                   v: null
    ...
     
    -        if (!_this3.rowObject.isValidSwap(row)) {
    +        if (!this.rowObject.isValidSwap(row)) {
    

    Maybe this makes a negative difference too.

blazey’s picture

The exception is thrown in the last line of this snippet

   Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) {
-    var _this3 = this;
-
     var rows = $(this.table.tBodies[0].rows).not(':hidden');
 
     var _loop = function _loop(n) {
+      var _this3 = this;
+
       var row = rows[n];
       var $row = $(row);
       var rowY = $row.offset().top;
@@ -546,21 +537,21 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
         }
 
       if (y > rowY - rowHeight && y < rowY + rowHeight) {
-        if (_this3.indentEnabled) {
-          if (Object.keys(_this3.rowObject.group).some(function (o) {
+        if (this.indentEnabled) {
+          if (Object.keys(this.rowObject.group).some(function (o) {
             return _this3.rowObject.group[o] === row;
           })) {
             return {
               v: null
             };
           }
-        } else if (row === _this3.rowObject.element) {
+        } else if (row === this.rowObject.element) {

this doesn't seem right :)

The npm version is 5 months old and there were 39 betas since then (https://github.com/babel/babel/releases), so the issue might have already been fixed. Even if so, we should probably wait until it's on npm.

dawehner’s picture

Do you want to try out this locally? Otherwise it might be worth reporting the problem.

chi’s picture

I am getting the following error with this patch.

$ yarn run watch:js --dir ../
yarn run v1.5.1
$ node ./scripts/js/babel-es6-watch.js --dir ../
/var/www/d8/docroot/core/node_modules/snapdragon/lib/parser.js:473
        throw new Error('no parsers registered for: "' + self.input.slice(0, 5) + '"');
        ^

Error: no parsers registered for: "]a(r)"
    at parse (/var/www/d8/docroot/core/node_modules/snapdragon/lib/parser.js:473:15)
    at Parser.parse (/var/www/d8/docroot/core/node_modules/snapdragon/lib/parser.js:477:24)
    at Snapdragon.parse (/var/www/d8/docroot/core/node_modules/snapdragon/index.js:122:28)
    at Snapdragon.<anonymous> (/var/www/d8/docroot/core/node_modules/braces/lib/braces.js:37:45)
    at Braces.parse (/var/www/d8/docroot/core/node_modules/braces/lib/braces.js:74:26)
    at Braces.expand (/var/www/d8/docroot/core/node_modules/braces/lib/braces.js:96:18)
    at create (/var/www/d8/docroot/core/node_modules/braces/index.js:142:15)
    at memoize (/var/www/d8/docroot/core/node_modules/braces/index.js:293:13)
    at Function.braces.create (/var/www/d8/docroot/core/node_modules/braces/index.js:161:10)
    at Function.braces.expand (/var/www/d8/docroot/core/node_modules/braces/index.js:82:17)
error An unexpected error occurred: "Command failed.
Exit code: 1
Command: sh
Arguments: -c node ./scripts/js/babel-es6-watch.js --dir ../
Directory: /var/www/d8/docroot/core
Output:
".
info If you think this is a bug, please open a bug report with the information provided in "/var/www/d8/docroot/core/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

The good news is that yarn run watch:js --dir ../modules works well. So the problem lays somewhere in core JS files.

chi’s picture

The good news is that yarn run watch:js --dir ../modules works well.

Well, it does not. The only change in processed file is "DO NOT EDIT THIS FILE." header. I wounder if Babel presets are picked correctly when the root directory is changed.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

blazey’s picture

Cool. Hopefully, it will hit npm soon: https://www.npmjs.com/package/babel-core.

chr.fritsch’s picture

babel 7.0 was released a month ago. Can we here proceed now?

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dawehner’s picture

Am I missing something in this PR? Why are we doing two things at a time:

  • Updating to babel 7.x
  • Enable usage for contrib and custom modules

I think focusing on just the later one would be a more successful strategy.

blazey’s picture

@dawehner see #6

babel-core prior to 7.0.0-alpha.3 has a bug in plugin resolution which makes it impossible to process any files that aren't inside the directory with package.json (see Transpile outside of node_module 'root'), so babel-core update was required.

Babel upgrade is not the goal of this issue, it was just a mean of making the solution work. There might be other ways of fixing it without a babel upgrade (the patch from #3047534: Allow core transpile tooling to work with files outside the default directory. maybe?).

wim leers’s picture

What exactly is this postponed on? On upstream features in babel? That was the state in #9 more than 14 months ago. Is that still true?

blazey’s picture

Status: Postponed » Needs review
StatusFileSize
new77.95 KB
new533.47 KB

Ok, it turns out that the approach in #3047534: Allow core transpile tooling to work with files outside the default directory. is limited compared to this one. It can only process a single file and it only supports the build command, watch is not supported. Babel 7 is around for a while now so here's the updated version of #6.

Please credit @alwaysworking for the work in the mentioned issue.

wim leers’s picture

droplet’s picture

Use `cwd` I'd say.

Furthermore,
If we need more flexible, I will export the whole chokidar options (, or the Drupal script options) via Cli or config.js or both.

things like this:
https://github.com/prettier/prettier/blob/master/src/cli/minimist.js

(There're some projects structures in Drupal is a bit odd, I believe config.js, a programmable config file is more suitable for Drupal. )

blazey’s picture

StatusFileSize
new109.7 KB

Thanks Wim.

@droplet we've discussed the method for passing the directory location in #5 and #6 and decided to go with the --dir as the most versatile option. For the other points, I agree a lot can be improved here. Some could even say that the javascript handling in drupal begs for improvement. Let's do one thing at a time though. This issue is about making it possible to use the current build system outside of the core/ directory. For other things please open new issues.

Does anyone know what's going on with the test builds above? They are turning neither red nor green and all the build page says is

line 0	File ignored because of a matching ignore pattern. Use "--no-ignore" to override.
GrandmaGlassesRopeMan’s picture

Status: Needs review » Needs work

I'm not sure this is the correct approach. From my perspective, this patch attempts to do too many things at once, making it quite difficult to review. If you wanted to the easiest path, excluding some limitations, to using core standards to transpile contrib JavaScript than the work in #3047534: Allow core transpile tooling to work with files outside the default directory. would have solved that problem. I'm still not sure I understand this need though.

However we've now perhaps resolved the original goal here, updated babel, and adjusted the output of all core JavaScript files. I would really suggest to break this up into a few smaller issues to make it more digestible for reviewers and committers.

Thanks.

blazey’s picture

Status: Needs work » Needs review
StatusFileSize
new248.03 KB

Thanks for checking @alwaysworking. This patch is actually tiny and the huge output comes from the fact that we don't use a build system and artifacts need to be committed to the repository.

Here's the breakdown of the changes:

  • Changes to package.json and yarn.lock. These are needed to get the version of babel in which the path resolution bug is fixed.
  • The real, hand-made :) changes to 3 files: babel-es6-build.js, babel-es6-watch.js and compile.js are the ones that really need to be reviewed. These fit on one screen. Here's a screenshot for convenience.
  • All the other stuff in the combined patch is the result of processing the existing core .es6.js files with the new version of babel. I would say we don't need to review them. They are there just to make sure that the testbot gives a thumbs-up.
lauriii’s picture

I don't really understand why core should contain code for doing ES6 to ES5 compilation to contrib. Usually, each project should be responsible for their own tooling. I'm wondering if a better approach would be to create a separate library for our compilation process that contrib projects could depend on if they want to.

johnwebdev’s picture

I don't really understand why core should contain code for doing ES6 to ES5 compilation to contrib.

For me it would be convenient and an easy way to ensure the JavaScript I write is compliant with the Drupal standards. I must admit I had issues to even get started.

https://www.drupal.org/docs/develop/standards/javascript/javascript-codi...

States that the reasonable coding standard is 'Airbnb JavaScript Style Guide'
And then there is a separate code standard list below.
And then if we look at the Airbnb JavaScript Style Guide we can see that ES5 is deprecated which means I should probably use ES6.

So if we decide, okay, let's go ES6

https://eslint.org/docs/user-guide/command-line-interface
https://www.drupal.org/node/1955232

These configuration files ship with Drupal 8 core and can be used from there.

.eslintrc.json
.eslintignore
In a Drupal 8 folder these configuration files will be automatically detected and used by ESLint when it is invoked from within the code base.

Following those instructions, which leads us to another problem: https://www.drupal.org/project/drupal/issues/3003522 where the suggestion is to set your own .eslintrc as root, which according to article above I shouldn't need to etc.

With that being said, all of the above could be solved by just improving the documentation and slightly and we're fine, but then again, if the contrib. module just needs some JavaScript for a change, or enhancement I'm not that keen to setup my own tooling. I just want something that works. For greater projects where JavaScript is a key of the module, sure, your own tooling makes more sense.

I'm wondering if a better approach would be to create a separate library for our compilation process that contrib projects could depend on if they want to.

Yeah, this approach would also solve the DX-issues I had above.

blazey’s picture

If you are willing to use an external tool then there's the webpack module. With webpack babel it not only transpiles the code but also makes it possible to include npm packages and takes care of the minification and bundle splitting. It can be used for core and custom libraries and provides a way to compile the ones in contrib in a way that doesn't require the webpack module to be added as a dependency. In general, it takes care of the webpack configuration and tries to make the process of bridging the JavaScript and Drupal worlds as easy as possible, while still allowing full customization through a pluggable architecture and not limiting the hosting options by supporting both commit-time and deploy-time builds. There's one problem with it though, it still seems to be hard to set up.

This issue is not about providing a perfect solution. It's about fixing a bug that makes it impossible to use a core tool in other folders. After it's fixed any drupal project will be able to use modern js with these 3 commands:

cd core
yarn
yarn watch:js --dir ../modules/custom

Why not just fix it?

blazey’s picture

BTW, rails 6 was released last Thursday. It comes with webpack by default https://weblog.rubyonrails.org/2019/8/15/Rails-6-0-final-release/.

At some point we might want to acknowledge the fact that JavaScript needs preprocessing. Same goes for css really. Or we can pretend they don't and just continue to party like it's 1999 :)

chi’s picture

At some point we might want to acknowledge the fact that JavaScript needs preprocessing.

I disagree. Browsers have made a big break in supporting ES6 and Drupal Core JavaScripts are mostly quiet simple. They are using ES6 features that are supported by all modern browsers.
https://caniuse.com/#search=es6
Once we drop support of Internet Explorer there will probably be no point to use Babel for compiling JavaScript.

Same applies to CSS. Custom properties make SASS less essential.

droplet’s picture

Preprocessor is still worth to introduce to Core. Packages like preset-env allow us to forget what we're writing for. However, for package bundlers, I think we need a proven before adding into Core. e.g.: Is it possible and how well the code splitting..etc. Personally, I don't like a mix of PHP & NODEJS code to get a simple thing work.

Second, I think when Drupal introduce these ES6 scripts into CORE, we (I) intended to make it CORE (@internal) only. At that time, I hope @internal allow the CORE JS development to move forward faster. I'm tried to see the word "BC, BC, BC". Therefore, I suggested in #26 for global configs. If we opening a hole, make everything configurable. Each option has a reason for a new patch.

In #26, cwd is a chokidar option. We need not create another --dir and write a doc to explain how it works. Or going to figure out the difference between these options.

#2658650: [META] Optimize Frontend Workflow in Core Development

wim leers’s picture

@lauriii Very, very few contrib modules will ever figure this out. If we want contrib to follow contrib's lead/example, then we should make it feasible to do so.

I think @johndevman's comment is accurate in describing how tricky it is to follow core's example. I also struggled with it while working on https://www.drupal.org/project/entity_embed a few months ago.

GrandmaGlassesRopeMan’s picture

@Wim Leers - I think the thing to understand is that core does things if a non-optimal way. There are original design constraints that force us to do the things the way we are currently. Contrib shouldn't feel constrained by these decisions.

wim leers’s picture

Sure. But even then it's up to core to provide guidance to contrib. If it can encourage contrib to do better than itself: wonderful! 😀🥳

lauriii’s picture

I think we agree that contrib is lacking proper tooling for ES6 to ES5 transpilation process. The easiest way forward would probably be creating a library that could be loaded through npm which is built without Drupal core limitations. We could also try to build proper tooling in core but that will likely take much longer. There's already some related discussion happening in #2873160: Implement core management of 3rd-party FE libraries.

I think, for now, we should say that the core ES6 compilation process is not supported beside what is needed for core since the workflow is suboptimal. As a result, we shouldn't fix bugs in the transpilation process, unless it affects core.

droplet’s picture

@johndevman's comment brings out many hidden issues:

- following the CORE way to develop
- following the CORE code standard
- Disconnect from CORE
- Enable CLI to lint codes.
- Enable editor to lint codes.
- Combine core & custom setup
-- etc..

To move the package.json one level up -- The only way to get these things done perfectly. (but not the NODEJS world preferred?)

For linting, the basic step you could do now without patch:

cd /core
yarn install --modules-folder ../core

To copy devDependencies doesn't work I think, now this doesn't specify the exact version for some packages. eg. "^17.0.0".

Or
(if you need your own package.json)

cp yarn.lock modules/custom/yarn.lock
cp package.json modules/custom/package.json
cd modules/custom
....... edit package.json.......
yarn

there's an installation problem on node side, you can't do it very straightly.
https://www.npmjs.com/package/eslint-config-airbnb

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

jcisio’s picture

Issue tags: -JavaScript +JavaScript

FWIW, it is currently possible to use core tooling to build (not watch) custom ES6 files. For example:

# in core/> yarn run build:js --file ../modules/custom/**/*.es6.js

However, I think there is some problem with the output (it is not really transpiled, just reformatted).

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

catch’s picture

Status: Needs review » Closed (outdated)

Closing as outdated now that the build step is no longer in use - contrib can just directly write ES6 JavaScript as soon as they drop compatibility with IE11.

#3278415: Remove usages of the JavaScript ES6 build step, the build step itself, and associated dev dependencies