Thanks to visit codestin.com
Credit goes to github.com

Skip to content

FullLink Scala.js-specific minifier #4482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dispalt opened this issue May 18, 2021 · 11 comments
Closed

FullLink Scala.js-specific minifier #4482

dispalt opened this issue May 18, 2021 · 11 comments
Assignees
Labels
enhancement Feature request (that does not concern language semantics, see "language")
Milestone

Comments

@dispalt
Copy link

dispalt commented May 18, 2021

Since modules are now supported and work great with scala.js, but don't work great with the Closure compiler, and apparently won't ever work with it. I think it would be great to have some sort of simple property name minifier. Current, good javascript minifiers do well with ES imports and are able to tree shake most of the unused stuff. They do well with class name minification as well. However, where they fail is property minification.

In scala.js we have access to a lot more semantic information so it might not be too tough to create a simple minification of property names, I think it would drastically reduce the output javascript size. Today the code is pretty compressable but it could be a lot better.

Another option could be some guidance on how to pass the right parameters to something like Terser if there were some conventions that were universally applicable. https://terser.org/docs/api-reference.html#mangle-properties-options

@gzm0
Copy link
Contributor

gzm0 commented May 22, 2021

Explanation of how mangling works: in terser: https://terser.org/docs/cli-usage#cli-mangling-property-names-mangle-props

@dispalt
Copy link
Author

dispalt commented Jun 1, 2021

so I actually did get some property mangling to work with terser. I don't know how safe it is so I have it disabled for now but I basically fed it some regexes of package names in our project together with these important options.

  1. nameCache, this makes sure it mangles the name to the same thing across files,
  2. parallel: false, this makes sure it doesn't process the name mangling in parallel, this is a webpack specific thing. Other runners like vite might do something different.
  3. keep_quoted: true, which as the option suggests won't mangle a name that ever appears quoted.

I used the following snippet, the reserved words I pulled from the ClosureLinkerBackend. I included some examples of packages this project uses. Anyways, not sure where to go with this outside of telling you I think it's possible with no work on the scalajs side, which is exciting.

{
    sourceMap: true,
    nameCache: {},
    format: {
      comments: false,
    },
    mangle: {
      properties: {
        debug: false,
        keep_quoted: true,
        reserved: ['$classData', 'main', 'toString', 'constructor', 'length', 'call', 'apply', 'NaN', 'Infinity', 'undefined'],
        regex: /^(Lweb|Lslinky|slinky|render__L|query__L|\$m_|.*__f_|Ljava|cats\$)/,
      }
    },
  }

@cquiroz
Copy link
Contributor

cquiroz commented Jun 4, 2021

I tried this and got a nice size reduction. However (I think this is expected) it doesn't work with dynamic loading. I think it won't know what names to call on the other js files if they are mangled independently

@dispalt
Copy link
Author

dispalt commented Jun 4, 2021

@cquiroz if you are talking about js.dynamicImport it worked for me with webpack 5. This is bundler specific, because it's highly dependent on how the bundler processes files, and nameCache being the "big" feature that makes it work.

@sjrd sjrd added the enhancement Feature request (that does not concern language semantics, see "language") label Jul 18, 2021
@sjrd sjrd changed the title FullLink scala.js minifier FullLink Scala.js-specific minifier Aug 2, 2021
@garhirunrat
Copy link

@cquiroz if you are talking about js.dynamicImport it worked for me with webpack 5. This is bundler specific, because it's highly dependent on how the bundler processes files, and nameCache being the "big" feature that makes it work.

It works but not ideal, still need a solution for mangle properties reserved and regex.

@gzm0
Copy link
Contributor

gzm0 commented Apr 24, 2022

I've had a look at the terser options, and it seems we should be able to make it work with Scala.js:

Doc: https://terser.org/docs/api-reference#mangle-properties-options

  • It supports closure style property renaming based on quoting (mangle.properties.keep_quoted: "strict")
  • It supports rewriting an existing source map.
  • It supports not renaming top-level definitions.
  • It supports reserved identifiers (which we might need for global scope idents in modules).
  • It supports reserved properties (which we might need to avoid name clashes with exports).
  • It supports multiple files as input.

Unclear to me is how to best integrate. To integrate it externally (based on the linking report only), we need to expose quite a bit of the guts of the linker:

  • optimizeBracketSelects = false
  • trackAllGlobalRefs = true (and add to report)
  • assemble all required exported properties (unclear whether these need to be all to avoid clashes, or only the ones for the corejslib).

On the flipside, we wouldn't have to do anything for sourcemaps.

@sjrd sjrd self-assigned this Dec 12, 2022
@viktor-podzigun
Copy link

viktor-podzigun commented Feb 7, 2023

Actually, multiple modules may also work with Closure Compiler, there is --chunk option for some time already (former is --module), more details are in this stackoverflow answer. Basic idea is to specify multiple output files (modules) along with their dependencies:

--js commonfunctions.js
--chunk common:1
--js page1functions.js
--js page1events.js
--chunk page1:2:common
--js page2function.js
--chunk page2:1:common

and Scala.js has knowledge about inter-module dependencies, right?

@sjrd
Copy link
Member

sjrd commented Feb 7, 2023

That's not the problem. We've known about that for a while.

The problem is mainly that GCC refuses to consider and preserve import statements to "the outside world" that is not under its control.

@ekrich
Copy link
Contributor

ekrich commented Feb 7, 2023

Is this one of the issues? google/closure-compiler#3707

@sjrd
Copy link
Member

sjrd commented Feb 7, 2023

All the details are already in #3893.

@viktor-podzigun
Copy link

viktor-podzigun commented Feb 7, 2023

@sjrd I was thinking of this limitation even when module kind is CommonJS:

require(moduleSet.modules.size <= 1,
        "Cannot use multiple modules with the Closure Compiler")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature request (that does not concern language semantics, see "language")
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants