DEV: @babel/plugin-proposal-decorators -> decorator-transforms (#25290)

decorator-transforms (https://github.com/ef4/decorator-transforms) is a modern replacement for babel's plugin-proposal-decorators. It provides a decorator implementation using modern browser features, without needing to enable babel's full suite of class feature transformations. This improves the developer experience and performance.

In local testing with Google's 'tachometer' tool, this reduces Discourse's 'init-to-render' time by around 3-4% (230ms -> 222ms).

It reduces our initial gzip'd JS payloads by 3.2% (2.43MB -> 2.35MB), or 7.5% (14.5MB -> 13.4MB) uncompressed.
This commit is contained in:
David Taylor 2024-05-08 10:40:51 +01:00 committed by GitHub
parent f74983e2e1
commit 0f4520867b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 151 additions and 12 deletions

View File

@ -6,6 +6,23 @@ const path = require("path");
module.exports = { module.exports = {
name: require("./package").name, name: require("./package").name,
options: {
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
},
// return an empty tree here as we do not want the addon modules to be // return an empty tree here as we do not want the addon modules to be
// included into vendor.js; instead, we will produce a separate bundle // included into vendor.js; instead, we will produce a separate bundle
// (admin.js) to be included via a script tag as needed // (admin.js) to be included via a script tag as needed

View File

@ -3,6 +3,23 @@
module.exports = { module.exports = {
name: require("./package").name, name: require("./package").name,
options: {
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
},
isDevelopingAddon() { isDevelopingAddon() {
return true; return true;
}, },

View File

@ -8,6 +8,21 @@ module.exports = {
handlebars: "handlebars/dist/cjs/handlebars.js", handlebars: "handlebars/dist/cjs/handlebars.js",
}, },
}, },
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
}, },
isDevelopingAddon() { isDevelopingAddon() {

View File

@ -97,11 +97,20 @@ module.exports = {
options: { options: {
babel: { babel: {
plugins: [require.resolve("deprecation-silencer")], plugins: [
require.resolve("deprecation-silencer"),
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
}, },
"ember-cli-babel": { "ember-cli-babel": {
throwUnlessParallelizable: true, throwUnlessParallelizable: true,
disableDecoratorTransforms: true,
}, },
"ember-this-fallback": { "ember-this-fallback": {

View File

@ -1,4 +1,5 @@
/* eslint-disable simple-import-sort/imports */ /* eslint-disable simple-import-sort/imports */
import "decorator-transforms/globals";
import "./loader-shims"; import "./loader-shims";
import "./global-compat"; import "./global-compat";
/* eslint-enable simple-import-sort/imports */ /* eslint-enable simple-import-sort/imports */

View File

@ -60,10 +60,20 @@ module.exports = function (defaults) {
"ember-cli-babel": { "ember-cli-babel": {
throwUnlessParallelizable: true, throwUnlessParallelizable: true,
disableDecoratorTransforms: true,
}, },
babel: { babel: {
plugins: [require.resolve("deprecation-silencer")], sourceMaps: false,
plugins: [
require.resolve("deprecation-silencer"),
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
}, },
vendorFiles: { vendorFiles: {

View File

@ -1,4 +1,5 @@
/* eslint-disable simple-import-sort/imports */ /* eslint-disable simple-import-sort/imports */
import Application from "../app";
import "./loader-shims"; import "./loader-shims";
/* eslint-enable simple-import-sort/imports */ /* eslint-enable simple-import-sort/imports */
@ -46,7 +47,6 @@ import deprecated from "discourse-common/lib/deprecated";
import { setDefaultOwner } from "discourse-common/lib/get-owner"; import { setDefaultOwner } from "discourse-common/lib/get-owner";
import { setupS3CDN, setupURL } from "discourse-common/lib/get-url"; import { setupS3CDN, setupURL } from "discourse-common/lib/get-url";
import { buildResolver } from "discourse-common/resolver"; import { buildResolver } from "discourse-common/resolver";
import Application from "../app";
import { loadSprites } from "../lib/svg-sprite-loader"; import { loadSprites } from "../lib/svg-sprite-loader";
import * as FakerModule from "@faker-js/faker"; import * as FakerModule from "@faker-js/faker";
import { setLoadedFaker } from "discourse/lib/load-faker"; import { setLoadedFaker } from "discourse/lib/load-faker";

View File

@ -2,7 +2,22 @@
module.exports = { module.exports = {
name: require("./package").name, name: require("./package").name,
options: {}, options: {
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
},
isDevelopingAddon() { isDevelopingAddon() {
return true; return true;
}, },

View File

@ -3,6 +3,23 @@
module.exports = { module.exports = {
name: require("./package").name, name: require("./package").name,
options: {
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
},
isDevelopingAddon() { isDevelopingAddon() {
return true; return true;
}, },

View File

@ -2,7 +2,22 @@
module.exports = { module.exports = {
name: require("./package").name, name: require("./package").name,
options: {}, options: {
babel: {
plugins: [
[
require.resolve("decorator-transforms"),
{
runEarly: true,
},
],
],
},
"ember-cli-babel": {
disableDecoratorTransforms: true,
},
},
isDevelopingAddon() { isDevelopingAddon() {
return true; return true;
}, },

View File

@ -19,7 +19,8 @@
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"polyfill-crypto.getrandomvalues": "^1.0.0", "polyfill-crypto.getrandomvalues": "^1.0.0",
"terser": "^5.31.0" "terser": "^5.31.0",
"decorator-transforms": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">= 18", "node": ">= 18",

View File

@ -19,6 +19,7 @@ globalThis.console = {
import { transform as babelTransform } from "@babel/standalone"; import { transform as babelTransform } from "@babel/standalone";
import HTMLBarsInlinePrecompile from "babel-plugin-ember-template-compilation"; import HTMLBarsInlinePrecompile from "babel-plugin-ember-template-compilation";
import { Preprocessor } from "content-tag"; import { Preprocessor } from "content-tag";
import DecoratorTransforms from "decorator-transforms";
import colocatedBabelPlugin from "ember-cli-htmlbars/lib/colocated-babel-plugin"; import colocatedBabelPlugin from "ember-cli-htmlbars/lib/colocated-babel-plugin";
import { precompile } from "ember-source/dist/ember-template-compiler"; import { precompile } from "ember-source/dist/ember-template-compiler";
import EmberThisFallback from "ember-this-fallback"; import EmberThisFallback from "ember-this-fallback";
@ -138,6 +139,8 @@ globalThis.transpile = function (source, options = {}) {
if (moduleId && !skipModule) { if (moduleId && !skipModule) {
plugins.push(["transform-modules-amd", { noInterop: true }]); plugins.push(["transform-modules-amd", { noInterop: true }]);
} }
commonPlugins.find((p) => p[0] === "decorator-transforms")[0] =
DecoratorTransforms;
plugins.push(...commonPlugins); plugins.push(...commonPlugins);
try { try {

View File

@ -6,7 +6,7 @@ require "json_schemer"
class Theme < ActiveRecord::Base class Theme < ActiveRecord::Base
include GlobalPath include GlobalPath
BASE_COMPILER_VERSION = 81 BASE_COMPILER_VERSION = 82
class SettingsMigrationError < StandardError class SettingsMigrationError < StandardError
end end

View File

@ -9,9 +9,7 @@ class DiscourseJsProcessor
# To generate a list of babel plugins used by ember-cli, set # To generate a list of babel plugins used by ember-cli, set
# babel: { debug: true } in ember-cli-build.js, then run `yarn ember build -prod` # babel: { debug: true } in ember-cli-build.js, then run `yarn ember build -prod`
DISCOURSE_COMMON_BABEL_PLUGINS = [ DISCOURSE_COMMON_BABEL_PLUGINS = [
["proposal-decorators", { legacy: true }], ["decorator-transforms", { runEarly: true }],
"proposal-class-properties",
"proposal-private-methods",
"proposal-class-static-block", "proposal-class-static-block",
"transform-parameters", "transform-parameters",
"proposal-export-namespace-from", "proposal-export-namespace-from",

View File

@ -0,0 +1,21 @@
diff --git a/node_modules/decorator-transforms/dist/index.js b/node_modules/decorator-transforms/dist/index.js
index fce3aeb..c23d8e4 100644
--- a/node_modules/decorator-transforms/dist/index.js
+++ b/node_modules/decorator-transforms/dist/index.js
@@ -4,10 +4,13 @@ import {
import "./chunk-CSAU5B4Q.js";
// src/index.ts
-import { createRequire } from "module";
+
import { ImportUtil } from "babel-import-util";
-var req = createRequire(import.meta.url);
-var { default: decoratorSyntax } = req("@babel/plugin-syntax-decorators");
+
+// https://github.com/ef4/decorator-transforms/pull/27
+import PluginSyntaxDecorators from "@babel/plugin-syntax-decorators";
+const decoratorSyntax = PluginSyntaxDecorators.default || PluginSyntaxDecorators;
+
function makeVisitor(babel) {
const t = babel.types;
return {

View File

@ -92,7 +92,7 @@ RSpec.describe DiscourseJsProcessor do
JS JS
result = DiscourseJsProcessor.transpile(script, "blah", "blah/mymodule") result = DiscourseJsProcessor.transpile(script, "blah", "blah/mymodule")
expect(result).to include("_applyDecoratedDescriptor") expect(result).to include("static #_ = dt7948.n")
end end
it "correctly transpiles widget hbs" do it "correctly transpiles widget hbs" do

View File

@ -251,7 +251,7 @@ RSpec.describe ThemeJavascriptCompiler do
expect(compiler.raw_content).to include( expect(compiler.raw_content).to include(
"define(\"discourse/theme-1/discourse/components/my-component\", [\"exports\",", "define(\"discourse/theme-1/discourse/components/my-component\", [\"exports\",",
) )
expect(compiler.raw_content).to include("_defineProperty(this, \"value\", \"foo\");") expect(compiler.raw_content).to include('value = "foo";')
expect(compiler.raw_content).to include("setComponentTemplate") expect(compiler.raw_content).to include("setComponentTemplate")
expect(compiler.raw_content).to include("createTemplateFactory") expect(compiler.raw_content).to include("createTemplateFactory")
end end