nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
23.71k stars 2.37k forks source link

@nx/webpack unable to completely drop IE support using custom Browserslist config #19072

Closed nathansom closed 5 months ago

nathansom commented 1 year ago

Current Behavior

I used @nx/webpack:webpack executor to bundle TypeScript files for production and I set custom Browserslist config in .browserslistrc with

> 1% 
last 2 versions 
Firefox ESR
not dead
not ie <= 11

However, the bundled file still shows traces of IE support and reference to ActiveXObject object, which is a critical issue for using my production code on Microsoft Power Platform as the platform's solution checker does not allow reference to browser specific API, especially the dead one. MicrosoftTeams-image (9)

Expected Behavior

IE support is totally dropped since I specified not dead and not ie 11 in the brwoserslist config. No reference to ActiveXObject or any other IE-specific API. The Microsoft Power Platform's solution validator should not detect an attempt to access or reference an API specific to unsupported browser.

GitHub Repo

No response

Steps to Reproduce

  1. Create a TypeScript file in src/lib that export an object containing a function:
    
    function funcA() {
    console.log("hello world")
    }

export { obj: { a: funcA} };


2. Set a target in `project.json` for build:

```json
"build-prod": {
      "executor": "@nx/webpack:webpack",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/libs/project-name",
        "main": "libs/project-name/src/index.ts",
        "webpackConfig": "libs/project-name/webpack.prod.js",
        "tsConfig": "libs/project-name/tsconfig.lib.json",
        "commonChunk": false,
        "runtimeChunk": false,
        "vendorChunk": false
      }
    }
  1. Create webpack.common.js:
const path = require("path");

module.exports = {
  entry: { fileName: "libs/project-name/src/lib/fileName.ts" },
  output: {
    filename: "project-name.[name].js",
    library: { export: "default", name: "projectName", type: "window" },
    path: path.resolve(__dirname, "../../dist/libs/project-name")
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            plugins: [
              ["@babel/plugin-transform-runtime", { corejs: 3 }],
              "@babel/plugin-transform-typescript"
            ]
          }
        }
      }
    ]
  },
  resolve: {
    extensions: [".ts", ".tsx"]
  }
};
  1. Create webpack.prod.js:
    
    const { composePlugins, withNx } = require("@nx/webpack"),
    { merge } = require("webpack-merge"),
    common = require("./webpack.common");

module.exports = composePlugins(withNx(), (config, { options, context }) => merge(config, common, { mode: "production", devtool: false }) );


5. Create tsconfig.json
```json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "module": "commonjs",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}
  1. Create tsconfig.lib.json

    {
    "extends": "./tsconfig.json",
    "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "declaration": true,
    "types": ["node"]
    },
    "include": ["src/**/*.ts"],
    "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"]
    }
  2. Create .browserslistrc at the root of project

> 1% 
last 2 versions 
Firefox ESR
not dead
not ie <= 11
  1. Run build-prod task

Nx Report

Node   : 18.15.0
   OS     : win32-x64
   npm    : 9.5.0

   nx (global)        : 16.1.0
   nx                 : 16.5.0
   @nx/js             : 16.5.0
   @nx/jest           : 16.5.0
   @nx/linter         : 16.5.0
   @nx/workspace      : 16.5.0
   @nrwl/workspace    : 15.9.4
   @nx/cypress        : 16.5.0
   @nx/devkit         : 16.5.0
   @nrwl/devkit       : 15.9.4
   @nx/eslint-plugin  : 16.5.0
   @nx/express        : 16.5.0
   @nx/next           : 16.5.0
   @nx/node           : 16.5.0
   @nx/react          : 16.5.0
   @nx/rollup         : 16.5.0
   @nx/storybook      : 16.5.0
   @nrwl/tao          : 16.5.0
   @nx/web            : 16.5.0
   @nx/webpack        : 16.5.0
   typescript         : 5.1.3
   ---------------------------------------
   Community plugins:
   @hcltech/powerplatform-catalog      : 2.2.0
   @hcltech/powerplatform-dataverse    : 2.6.0
   @hcltech/powerplatform-init         : 3.0.0
   @hcltech/powerplatform-pac          : 3.0.0
   @hcltech/powerplatform-pcf          : 3.1.1
   @hcltech/powerplatform-react        : 1.0.1
   @hcltech/powerplatform-solution     : 3.0.0
   @hcltech/powerplatform-web-resource : 3.0.0
   @nx-plus/docusaurus                 : 15.0.0-rc.0
   ---------------------------------------
   Local workspace plugins:
         @mbap/financial-services/models
         @mbap/financial-services/ui
         @mbap/skunk-works/pcfs/physician-lookup-card
         @mbap/utils/authentication/graph-api
         @mbap/utils/authentication/dataverse
         @mbap/power-packs/power-hashtag/ui
         @mbap/utils/authentication/react
         @mbap/utils/authentication/msal
         @mbap/utils/authentication/next
         @mbap/utils/parser/csvParser
         @mbap/utils/authentication/b2c
         @mbap/team-onboarding/ui
         @mbap/natwest/models
         @mbap/natwest/utils
         @mbap/workforce/models
         @mbap/natwest/ui
         @mbap/banking/utils
         @mbap/api/open-weather
         @mbap/workforce/ui
         @mbap/api/polygon-io
         @mbap/banking/ui
         @mbap/ui/fluentui/v9
         @mbap/ui/fluentui/v8
         @mbap/ideas-forum/models
         @mbap/ui/shoelace
         @mbap/skunk-works/models
         @mbap/power-packs/models
         @mbap/api/nhtsa
         @mbap/power-packs/utils
         @mbap/ideas-forum/react
         @mbap/skunk-works/utils
         @mbap/pcf/utils
         @mbap/ideas-forum/next
         @mbap/skunk-works/ui
         @mbap/ui/visx
         @mbap/ideas-forum/ui
         @mbap/power-packs/ui
         @mbap/ui/mgt
         @mbap/models
   ---------------------------------------
   The following packages should match the installed version of nx
     - @nrwl/workspace@15.9.4
     - @nrwl/devkit@15.9.4

Failure Logs

No response

Package Manager Version

No response

Operating System

Additional Information

No response

ziacik commented 9 months ago

I have this exact problem. So far I've found this is a problem when using nx's babel preset. If I switch to @babel/env, the browserslist is respected. But then I'm not sure what else does the nx's preset do and if I can switch away from it.

The problem with the nx's preset is, when babel gets to handle the polyfills, it gets some weird default list of targets which includes some old versions of browsers, and mobile browsers too. The correct list of targets is there too in a "context" var, but isn't used for some reason.

Please fix.

ziacik commented 9 months ago

Here are some of my observations.

This seems to be somehow related to the isModern setting which, when set to true, sets targets to { esmodules: 'intersect' }.

https://github.com/nrwl/nx/blob/b6d2f88e8202373188fafcb679e230342c30e2d1/packages/js/babel.ts#L63

The isModern setting seems to be hardcoded to true everywhere (I'm confused - does this mean we can't build against non-modern browsers now?).

https://github.com/nrwl/nx/blob/396ffc463647c53436218639a5a7b31777befbf0/packages/webpack/src/plugins/nx-webpack-plugin/lib/compiler-loaders.ts#L66

Now I'm not sure what is the esmodules: 'intersect' setting meant to do. I guess it means the babel should take the targets calculated according to the browserslist and intersect it with targets which allow es modules. The problem is, if this is set, babel actually doesn't pick up the browserslist and it just uses the default list of targets for es modules, which contains rather old versions of many browsers, including mobile ones.

It could be because here in babel https://github.com/babel/babel/blob/5ebab544af2f1c6fc6abdaae6f4e5426975c9a16/packages/babel-helper-compilation-targets/src/index.ts#L178

the configPath is the workspace root, not the root of the application, so babel will not find the browserslist there.

Upon further debugging I noticed that here

https://github.com/babel/babel/blob/0058b7fef4d028d2826645b28e3b448517cd979d/packages/babel-helper-plugin-utils/src/index.js#L13

the dirname variable does contain the application root dir, but as it is passed further, it is completely ignored (the third param is not used) here

https://github.com/babel/babel/blob/0058b7fef4d028d2826645b28e3b448517cd979d/packages/babel-preset-react/src/index.js#L8

and here

https://github.com/babel/babel/blob/47ad54a057ed660bdc524ee26a00d5e985696d34/packages/babel-preset-env/src/index.js#L275

But this is how it is for a long time already in babel, so I really don't know if this is a bug or not. All I know is that if I use that third param to set configPath, the browserslist config gets picked and everything works as it should.

I'd appreciate if someone more capable than me looked into this and said if this is a bug in nx or if it is a bug in babel which I could file.

Please forgive me, just to raise attention, let me tag you @FrozenPandaz since this looks (to me) like quite a big deal.

nathansom commented 9 months ago

Thanks for sharing @ziacik! I actually have resolved this issue a while ago by removing @babel/plugin-transform-runtime from the plugins array. Browserlist isn't even needed anymore and the bundled JS passed the validator that really hates IE.

Still, I am hoping that there will be a more detailed documentation for Nx's presets for what configurations that are already included.

Coly010 commented 5 months ago

this does appear to be an issue with Babel itself.

There are two similar issues reported on their repo currently: https://github.com/babel/babel/issues/9429 and https://github.com/babel/babel/issues/7758

Where browserslist is not being respected correctly based on where it is defined.

As such, I'm going to close this issue.

github-actions[bot] commented 4 months ago

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.