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

Cannot assign to read only property 'exports' of object '#<Object>' (mix require and export) #4039

Open
DimitryDushkin opened this Issue Jan 19, 2017 · 69 comments

Comments

Projects
None yet
@DimitryDushkin

DimitryDushkin commented Jan 19, 2017

Do you want to request a feature or report a bug?
bug

What is the current behavior?
Module with code

// 'a.js'
module.exports = { a: 'b' };

// b.js
const a = require('./a.js').a;

export default {
   aa: a
}

Gives error:

Cannot assign to read only property 'exports' of object '#<Object>'

Appeared after upgrade webpack 2.2.0.rc.6 -> 2.2.0.

If 'harmony-module' is ES2015 module, then looks like it's now impossible to mix require and export default in single module. If it so, that's okay, but should be mentioned in docs.

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.
MacOS 10.12.2
node.js 6.9.2
webpack 2.2

@DimitryDushkin DimitryDushkin changed the title from Cannot assign to read only property 'exports' of object '#<Object>' to Cannot assign to read only property 'exports' of object '#<Object>' (mix require and export) Jan 19, 2017

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Jan 19, 2017

Member

The code above is ok. You can mix require and export. You can't mix import and module.exports.

Member

sokra commented Jan 19, 2017

The code above is ok. You can mix require and export. You can't mix import and module.exports.

@DimitryDushkin

This comment has been minimized.

Show comment
Hide comment
@DimitryDushkin

DimitryDushkin Jan 19, 2017

@sokra probably in real code I had something more, that caused the issue. Now I've refactored this part to import export and it works fine.

I'll try check it in more clear example. For now I believe the issue can be closed.

DimitryDushkin commented Jan 19, 2017

@sokra probably in real code I had something more, that caused the issue. Now I've refactored this part to import export and it works fine.

I'll try check it in more clear example. For now I believe the issue can be closed.

@jchv

This comment has been minimized.

Show comment
Hide comment
@jchv

jchv Jan 19, 2017

This issue was newly affecting me after instructing Babel to not transpile module syntax. As sokra described, it only occurred when trying to use CommonJS style module.exports inside of ES modules. require always works. This can be fixed by simply replacing all module.exports = ... to export default ... where applicable, as this is seemingly equivalent for old Babel-style ES module transpilation. (Note though, that importing this module using require will probably give you an option with a default key rather than the default export itself, so it's probably best you make the switch across the entire codebase at once.)

jchv commented Jan 19, 2017

This issue was newly affecting me after instructing Babel to not transpile module syntax. As sokra described, it only occurred when trying to use CommonJS style module.exports inside of ES modules. require always works. This can be fixed by simply replacing all module.exports = ... to export default ... where applicable, as this is seemingly equivalent for old Babel-style ES module transpilation. (Note though, that importing this module using require will probably give you an option with a default key rather than the default export itself, so it's probably best you make the switch across the entire codebase at once.)

@ggoodman

This comment has been minimized.

Show comment
Hide comment
@ggoodman

ggoodman Jan 19, 2017

I find myself also being bitten by this issue since upgrading to 2.2.0. In my case, my hypothesis is a require chain that looks like:

CommonJSModule --requires--> ESModule --requires--> AnotherCommonJSModule

I'm sorry that I can't provide any more details at this time.

ggoodman commented Jan 19, 2017

I find myself also being bitten by this issue since upgrading to 2.2.0. In my case, my hypothesis is a require chain that looks like:

CommonJSModule --requires--> ESModule --requires--> AnotherCommonJSModule

I'm sorry that I can't provide any more details at this time.

@ggoodman

This comment has been minimized.

Show comment
Hide comment
@ggoodman

ggoodman Jan 20, 2017

I'm not at all familiar with the internals but a quick, manual binary search suggests the regression is here: v2.2.0-rc.4...v2.2.0-rc.5

Attn: @sokra, @TheLarkInn I think this issue should be re-opened.

ggoodman commented Jan 20, 2017

I'm not at all familiar with the internals but a quick, manual binary search suggests the regression is here: v2.2.0-rc.4...v2.2.0-rc.5

Attn: @sokra, @TheLarkInn I think this issue should be re-opened.

@jchv

This comment has been minimized.

Show comment
Hide comment
@jchv

jchv Jan 20, 2017

Taking a quick glance, this is definitely the culprit:

a7a4184

detect harmony modules before parsing
exports is now undefined in ESM
module.exports is now read-only in ESM and returns undefined
define is now undefined in ESM

As it says, module.exports is read-only in ES modules. If you're getting module.exports as read-only in a CommonJS module, THAT would be a bug, but that file is very much not a CommonJS file if it contains any export/import statements. I can confirm that this was the problem in my case and it was fixed by making my ES modules properly use ES exports. As a note require still works just fine inside of any module.

From my PoV it seems like Webpack's new behavior ultimately makes a lot more sense than the old behavior. It is fairly inane to allow mixing of import statements and CommonJS module.exports, and probably was never intended to work that way.

jchv commented Jan 20, 2017

Taking a quick glance, this is definitely the culprit:

a7a4184

detect harmony modules before parsing
exports is now undefined in ESM
module.exports is now read-only in ESM and returns undefined
define is now undefined in ESM

As it says, module.exports is read-only in ES modules. If you're getting module.exports as read-only in a CommonJS module, THAT would be a bug, but that file is very much not a CommonJS file if it contains any export/import statements. I can confirm that this was the problem in my case and it was fixed by making my ES modules properly use ES exports. As a note require still works just fine inside of any module.

From my PoV it seems like Webpack's new behavior ultimately makes a lot more sense than the old behavior. It is fairly inane to allow mixing of import statements and CommonJS module.exports, and probably was never intended to work that way.

@DimitryDushkin

This comment has been minimized.

Show comment
Hide comment
@DimitryDushkin

DimitryDushkin Jan 20, 2017

Maybe add this info to migration guide?

DimitryDushkin commented Jan 20, 2017

Maybe add this info to migration guide?

@ggoodman

This comment has been minimized.

Show comment
Hide comment
@ggoodman

ggoodman Jan 20, 2017

I can only speak for myself, but for the situation affecting me the module within which module.exports is read-only does not have any import or export statements. It appears that the heuristic that is identifying the file in question as a 'harmony' model is misfiring in some situations.

ggoodman commented Jan 20, 2017

I can only speak for myself, but for the situation affecting me the module within which module.exports is read-only does not have any import or export statements. It appears that the heuristic that is identifying the file in question as a 'harmony' model is misfiring in some situations.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Jan 20, 2017

Member

@ggoodman are you using babel-runtime?

Member

sokra commented Jan 20, 2017

@ggoodman are you using babel-runtime?

@ggoodman

This comment has been minimized.

Show comment
Hide comment
@ggoodman

ggoodman Jan 20, 2017

@sokra here are the relevant config files:

.babelrc:

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ],
  "plugins": ["transform-runtime", "syntax-dynamic-import"]
}

webpack.config.js (simplified):

'use strict';

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Path = require('path');
const Webpack = require('webpack');


const config = {
    cache: true,
    devtool: process.env.NODE_ENV !== 'production' ? 'source-map' : false,
    context: Path.join(__dirname),
    output: {
        path: Path.join(__dirname, 'build'),
        filename: '[name].js',
        chunkFilename: '[name].js',
        publicPath: '/static/',
    },
    recordsPath: Path.join(__dirname, 'recordsCache'),
    module: {
        rules: [{
                test: /\js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'ng-annotate-loader',
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true,
                        },
                    },
                    {
                        loader: 'string-replace-loader',
                        options: {
                            multiple: [
                                { search: /API_URL/g, replace: process.env['PLUNKER_API_URL'] },
                                { search: /EMBED_URL/g, replace: process.env['PLUNKER_EMBED_URL'] },
                                { search: /RUN_URL/g, replace: process.env['PLUNKER_RUN_URL'] },
                                { search: /SHOT_URL/g, replace: process.env['PLUNKER_SHOT_URL'] },
                                { search: /WWW_URL/g, replace: process.env['PLUNKER_WWW_URL'] },
                            ],
                        },
                    },
                ]
            },
        ],
    },
    plugins: [
        new ExtractTextPlugin({
            filename: '[name].css',
            disable: false,
            allChunks: true,
        }),
    ],
    resolve: {
        modules: [
            Path.join(__dirname, 'node_modules'),
            Path.join(__dirname, 'src'),
        ],
    },
};

module.exports = config;

ggoodman commented Jan 20, 2017

@sokra here are the relevant config files:

.babelrc:

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ],
  "plugins": ["transform-runtime", "syntax-dynamic-import"]
}

webpack.config.js (simplified):

'use strict';

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Path = require('path');
const Webpack = require('webpack');


const config = {
    cache: true,
    devtool: process.env.NODE_ENV !== 'production' ? 'source-map' : false,
    context: Path.join(__dirname),
    output: {
        path: Path.join(__dirname, 'build'),
        filename: '[name].js',
        chunkFilename: '[name].js',
        publicPath: '/static/',
    },
    recordsPath: Path.join(__dirname, 'recordsCache'),
    module: {
        rules: [{
                test: /\js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'ng-annotate-loader',
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true,
                        },
                    },
                    {
                        loader: 'string-replace-loader',
                        options: {
                            multiple: [
                                { search: /API_URL/g, replace: process.env['PLUNKER_API_URL'] },
                                { search: /EMBED_URL/g, replace: process.env['PLUNKER_EMBED_URL'] },
                                { search: /RUN_URL/g, replace: process.env['PLUNKER_RUN_URL'] },
                                { search: /SHOT_URL/g, replace: process.env['PLUNKER_SHOT_URL'] },
                                { search: /WWW_URL/g, replace: process.env['PLUNKER_WWW_URL'] },
                            ],
                        },
                    },
                ]
            },
        ],
    },
    plugins: [
        new ExtractTextPlugin({
            filename: '[name].css',
            disable: false,
            allChunks: true,
        }),
    ],
    resolve: {
        modules: [
            Path.join(__dirname, 'node_modules'),
            Path.join(__dirname, 'src'),
        ],
    },
};

module.exports = config;
@joshlasdin

This comment has been minimized.

Show comment
Hide comment
@joshlasdin

joshlasdin Jan 20, 2017

Chiming in as I'm getting this error in the browser as well, but neither the requiring module, nor the required module have any import or export statements in them. I am using transform-runtime if that's relevant.

joshlasdin commented Jan 20, 2017

Chiming in as I'm getting this error in the browser as well, but neither the requiring module, nor the required module have any import or export statements in them. I am using transform-runtime if that's relevant.

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Jan 20, 2017

Member

transform-runtime adds import to your files...

Member

sokra commented Jan 20, 2017

transform-runtime adds import to your files...

@ggoodman

This comment has been minimized.

Show comment
Hide comment
@ggoodman

ggoodman Jan 20, 2017

@sokra I was not aware that this plugin would add import to my files.

If removing that plugin is a solution, what alternative can we consider so that we don't have babel-runtime stuff like _classCallCheck included for every source file using ES6 features like classes?

ggoodman commented Jan 20, 2017

@sokra I was not aware that this plugin would add import to my files.

If removing that plugin is a solution, what alternative can we consider so that we don't have babel-runtime stuff like _classCallCheck included for every source file using ES6 features like classes?

@jchv

This comment has been minimized.

Show comment
Hide comment
@jchv

jchv Jan 21, 2017

The way I see it, there are a few good solutions:

  • Make transform-runtime support outputting require statements instead of import statements, as an option. This seems unlikely, because it looks like Babel is already relying on the fact that import is declarative.
  • Use transform-es2015-modules-commonjs. This would replace all import statements with require statements. If you are not using any import/export syntax in your app, this solution is probably ideal, because it incurs no extra cost. However, if you are using ES modules, then this will likely impact Webpack 2's ability to perform tree shaking. (I'm sure everyone is aware of this.)
  • Use ES modules across the board. I think this is the most correct thing to do. Is there a reason why existing CommonJS exports can't simply be migrated? require does not have to be globally replaced, only module.exports and exports statements.

jchv commented Jan 21, 2017

The way I see it, there are a few good solutions:

  • Make transform-runtime support outputting require statements instead of import statements, as an option. This seems unlikely, because it looks like Babel is already relying on the fact that import is declarative.
  • Use transform-es2015-modules-commonjs. This would replace all import statements with require statements. If you are not using any import/export syntax in your app, this solution is probably ideal, because it incurs no extra cost. However, if you are using ES modules, then this will likely impact Webpack 2's ability to perform tree shaking. (I'm sure everyone is aware of this.)
  • Use ES modules across the board. I think this is the most correct thing to do. Is there a reason why existing CommonJS exports can't simply be migrated? require does not have to be globally replaced, only module.exports and exports statements.
@blckt

This comment has been minimized.

Show comment
Hide comment
@blckt

blckt Jan 23, 2017

How i can reproduce module.exports behavior?
I had entry point with name LoginPage, i need to build library with the same name, after that i init it on the page using new LoginPage();
Now i should use new LoginPage.LoginPage() or new LoginPage.default();
How i can resolve this issue?

blckt commented Jan 23, 2017

How i can reproduce module.exports behavior?
I had entry point with name LoginPage, i need to build library with the same name, after that i init it on the page using new LoginPage();
Now i should use new LoginPage.LoginPage() or new LoginPage.default();
How i can resolve this issue?

@sokra

This comment has been minimized.

Show comment
Hide comment
@sokra

sokra Jan 26, 2017

Member

adding import (by transform-runtime) also means that the file is switched into strict mode, which could break you code. In my opinion transform-runtime should be changed.

Member

sokra commented Jan 26, 2017

adding import (by transform-runtime) also means that the file is switched into strict mode, which could break you code. In my opinion transform-runtime should be changed.

@rozzzly

This comment has been minimized.

Show comment
Hide comment
@rozzzly

rozzzly Jan 29, 2017

I had the following .babelrc

{
    "presets": [
        [
            "es2015",
            {
                "modules": false
            }
        ],
        "stage-0",
        "react"
    ],
    "plugins": [
        "add-module-exports",
        "transform-class-properties",
        "transform-object-rest-spread",
        "transform-object-assign"
    ]
}

And was able to fix this by removing the add-module-exports plugin. TBH, I can't even recall why I had it in there to begin with... but upon removal it started working as expected. Nobody else has mentioned add-module-exports yet so I thought I'd chime in too to point out that it's not just transform-runtime causing this.

rozzzly commented Jan 29, 2017

I had the following .babelrc

{
    "presets": [
        [
            "es2015",
            {
                "modules": false
            }
        ],
        "stage-0",
        "react"
    ],
    "plugins": [
        "add-module-exports",
        "transform-class-properties",
        "transform-object-rest-spread",
        "transform-object-assign"
    ]
}

And was able to fix this by removing the add-module-exports plugin. TBH, I can't even recall why I had it in there to begin with... but upon removal it started working as expected. Nobody else has mentioned add-module-exports yet so I thought I'd chime in too to point out that it's not just transform-runtime causing this.

@wangdahoo

This comment has been minimized.

Show comment
Hide comment
@wangdahoo

wangdahoo commented Feb 4, 2017

M

@kenberkeley

This comment has been minimized.

Show comment
Hide comment
@kenberkeley

kenberkeley Apr 19, 2018

Removing "modules: false" in .babelrc might work

kenberkeley commented Apr 19, 2018

Removing "modules: false" in .babelrc might work

@exarus

This comment has been minimized.

Show comment
Hide comment
@exarus

exarus Apr 21, 2018

Faced this issue when imported .js with ES6 class and module.exports = into my vue-cli project.
Webpack config:

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    resolve('src'),
    resolve('test'),
    resolve('node_modules/webpack-dev-server/client'),
    resolve('node_modules/my-class-module'),
  ]
},

babel config:

{
  "presets": [
    ["env", {
      "modules": false,
      "useBuiltIns": true,
    }],
    "stage-2"
  ],
  "plugins": ["transform-vue-jsx", "transform-runtime"],
}

Included class:

class MyClass {}
module.exports = MyClass;

exarus commented Apr 21, 2018

Faced this issue when imported .js with ES6 class and module.exports = into my vue-cli project.
Webpack config:

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    resolve('src'),
    resolve('test'),
    resolve('node_modules/webpack-dev-server/client'),
    resolve('node_modules/my-class-module'),
  ]
},

babel config:

{
  "presets": [
    ["env", {
      "modules": false,
      "useBuiltIns": true,
    }],
    "stage-2"
  ],
  "plugins": ["transform-vue-jsx", "transform-runtime"],
}

Included class:

class MyClass {}
module.exports = MyClass;
@bitcot

This comment has been minimized.

Show comment
Hide comment
@bitcot

bitcot Apr 21, 2018

@kenberkeley it did solve for me, can you help explaining why would it work ?

bitcot commented Apr 21, 2018

@kenberkeley it did solve for me, can you help explaining why would it work ?

@kenberkeley

This comment has been minimized.

Show comment
Hide comment
@kenberkeley

kenberkeley Apr 21, 2018

@bitcot I guessed, I tried, it worked, no explanation...

kenberkeley commented Apr 21, 2018

@bitcot I guessed, I tried, it worked, no explanation...

@yesmeck yesmeck referenced this issue May 8, 2018

Merged

Don't mix import and module.exports #1318

2 of 10 tasks complete

oimou added a commit to soramitsu/iroha-wallet-js that referenced this issue May 25, 2018

Use @babel/polyfill instead of @babel/transform-runtime
in order to load iroha-util.js as is.
According to the comment below, transform-runtime adds `import` to each file and makes it unable to use `module.exports`.
webpack/webpack#4039 (comment)

dotview added a commit to Aiyoumi-FE/one-team-server that referenced this issue Jul 5, 2018

Illyrix added a commit to Airyworks/scarlet that referenced this issue Aug 8, 2018

eyasliu added a commit to eyasliu/electron-startkit that referenced this issue Sep 4, 2018

@Zdend

This comment has been minimized.

Show comment
Hide comment
@Zdend

Zdend Sep 6, 2018

For me the problem disappeared after setting modules to "commonjs". Note that I was using one .babelrc file for both node environment and browser env.

"presets": [
    ["@babel/env", {
      "useBuiltIns": "entry",
      "targets": ["> 5%", "ie 9"],
      "modules": "commonjs"
    }]
  ]

Zdend commented Sep 6, 2018

For me the problem disappeared after setting modules to "commonjs". Note that I was using one .babelrc file for both node environment and browser env.

"presets": [
    ["@babel/env", {
      "useBuiltIns": "entry",
      "targets": ["> 5%", "ie 9"],
      "modules": "commonjs"
    }]
  ]
@noppa

This comment has been minimized.

Show comment
Hide comment
@noppa

noppa Sep 6, 2018

@Zdend Note that you'll miss out on tree shaking by doing that.

noppa commented Sep 6, 2018

@Zdend Note that you'll miss out on tree shaking by doing that.

@loganfsmyth

This comment has been minimized.

Show comment
Hide comment
@loganfsmyth

loganfsmyth Sep 7, 2018

Contributor

Now that Babel 7.x is out, I'll just say that this should essentially be resolved. The only time you should see this, with Babel 7.x, is if you're doing one of:

  1. You've actually using import and module.exports in the same file, which is not allowed by Webpack. You can sidestep this by setting "modules": "commonjs", which will make Babel compile the import to a require. This breaks tree shaking, as mentioned above though, so fixing your code would be a better idea.
  2. You're using useBultins: 'entry'/'usage, or @babel/plugin-transform-runtime, and you are running Babel on CommonJS files (either your own, or in random node_modules, if you're trying to compile that). Babel assumes files are ES modules by default, meaning those transforms would insert import statements into your file, triggering case 1. above. You can avoid this issue by setting sourceType: "unambiguous" in your Babel configuration, which will tell it to guess the type, like Webpack does, instead of assuming all files are modules.

@Zdend You could be hitting either or both of these cases, it is hard to say.

Contributor

loganfsmyth commented Sep 7, 2018

Now that Babel 7.x is out, I'll just say that this should essentially be resolved. The only time you should see this, with Babel 7.x, is if you're doing one of:

  1. You've actually using import and module.exports in the same file, which is not allowed by Webpack. You can sidestep this by setting "modules": "commonjs", which will make Babel compile the import to a require. This breaks tree shaking, as mentioned above though, so fixing your code would be a better idea.
  2. You're using useBultins: 'entry'/'usage, or @babel/plugin-transform-runtime, and you are running Babel on CommonJS files (either your own, or in random node_modules, if you're trying to compile that). Babel assumes files are ES modules by default, meaning those transforms would insert import statements into your file, triggering case 1. above. You can avoid this issue by setting sourceType: "unambiguous" in your Babel configuration, which will tell it to guess the type, like Webpack does, instead of assuming all files are modules.

@Zdend You could be hitting either or both of these cases, it is hard to say.

@Zdend

This comment has been minimized.

Show comment
Hide comment
@Zdend

Zdend Sep 7, 2018

@noppa @loganfsmyth thanks guys, tree shaking (or at least a big part of it) was really disabled. After removing modules attribute completely, client js bundles got considerably smaller.

It didn't however fully enable tree shaking - when I tried to add a named export function to a file that was only referenced by named imports and my new function wasn't used anywhere, set sideEffects to false, the function was still included in the bundle.

This is my .babelrc for both client and server

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": [
          "> 5%",
          "ie 11"
        ]
      }
    ]
  ],
  "plugins": [
     "@babel/plugin-transform-runtime",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-syntax-do-expressions",
    "@babel/plugin-proposal-do-expressions",
    "@babel/transform-flow-strip-types",
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ],
  "compact": false,
  "env": {
    "test": {
      "plugins": [
        "dynamic-import-node"
      ]
    }
  },
  "overrides": [
    {
      "test": [
        "**/src/scripts/**"
      ],
      "presets": [
        "@babel/react"
      ],
      "plugins": [
        "react-hot-loader/babel",
        "babel-plugin-flow-react-proptypes",
        "@babel/transform-flow-strip-types",
        "@babel/syntax-dynamic-import"
      ]
    },
    {
      "test": [
        "**/server/**",
        "**/config/**"
      ],
      "sourceType": "unambiguous",
      "presets": [
        [
          "@babel/env",
          {
            "targets": {
              "node": "current"
            },
            "modules": "commonjs"
          }
        ]
      ]
    }
  ]
}

However, by doing that I broke my node server that relies on node_modules and my server side code which is only using import/export statements. The problem is that one of the modules (newrelic) requires my config file (which uses import/export) but newrelic only expects old require/ exports syntax but I also need to reference that file in files with import syntax so then either newrelic is happy or my code using import/export is happy. Of course if I run it with babel-node directly there are no issues, only if I try to precompile it. I also tried to whitelist a particular file in webpack-node-externals which didn't help, sourceType setting to unambiguous or removing useBuiltIns config or @babel/plugin-transform-runtime didn't help in my case or perhaps I didn't do it right.

{
    mode: process.env.NODE_ENV || 'production',
    target: 'node',
    node: {
        __dirname: false,
        __filename: false,
    },
    externals: [nodeExternals({
        whitelist: ['config/utils/config-file', 'newrelic/lib/config']
    })],
    entry: {
        server: [
            './server/index.js'
        ]
    },
    output: {
        path: resolveRoot('/build-server'),
        filename: 'index.js'
    },
    module: {
        rules: [{
            test: /\.js$/,
            use: {
                loader: 'babel-loader'
            }
        }]
    },
    bail: true
}

Zdend commented Sep 7, 2018

@noppa @loganfsmyth thanks guys, tree shaking (or at least a big part of it) was really disabled. After removing modules attribute completely, client js bundles got considerably smaller.

It didn't however fully enable tree shaking - when I tried to add a named export function to a file that was only referenced by named imports and my new function wasn't used anywhere, set sideEffects to false, the function was still included in the bundle.

This is my .babelrc for both client and server

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": [
          "> 5%",
          "ie 11"
        ]
      }
    ]
  ],
  "plugins": [
     "@babel/plugin-transform-runtime",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-syntax-do-expressions",
    "@babel/plugin-proposal-do-expressions",
    "@babel/transform-flow-strip-types",
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ],
  "compact": false,
  "env": {
    "test": {
      "plugins": [
        "dynamic-import-node"
      ]
    }
  },
  "overrides": [
    {
      "test": [
        "**/src/scripts/**"
      ],
      "presets": [
        "@babel/react"
      ],
      "plugins": [
        "react-hot-loader/babel",
        "babel-plugin-flow-react-proptypes",
        "@babel/transform-flow-strip-types",
        "@babel/syntax-dynamic-import"
      ]
    },
    {
      "test": [
        "**/server/**",
        "**/config/**"
      ],
      "sourceType": "unambiguous",
      "presets": [
        [
          "@babel/env",
          {
            "targets": {
              "node": "current"
            },
            "modules": "commonjs"
          }
        ]
      ]
    }
  ]
}

However, by doing that I broke my node server that relies on node_modules and my server side code which is only using import/export statements. The problem is that one of the modules (newrelic) requires my config file (which uses import/export) but newrelic only expects old require/ exports syntax but I also need to reference that file in files with import syntax so then either newrelic is happy or my code using import/export is happy. Of course if I run it with babel-node directly there are no issues, only if I try to precompile it. I also tried to whitelist a particular file in webpack-node-externals which didn't help, sourceType setting to unambiguous or removing useBuiltIns config or @babel/plugin-transform-runtime didn't help in my case or perhaps I didn't do it right.

{
    mode: process.env.NODE_ENV || 'production',
    target: 'node',
    node: {
        __dirname: false,
        __filename: false,
    },
    externals: [nodeExternals({
        whitelist: ['config/utils/config-file', 'newrelic/lib/config']
    })],
    entry: {
        server: [
            './server/index.js'
        ]
    },
    output: {
        path: resolveRoot('/build-server'),
        filename: 'index.js'
    },
    module: {
        rules: [{
            test: /\.js$/,
            use: {
                loader: 'babel-loader'
            }
        }]
    },
    bail: true
}
@flyyang

This comment has been minimized.

Show comment
Hide comment
@flyyang

flyyang Sep 7, 2018

Contributor

Thanks @loganfsmyth

Short answer。

If you are using babel 7 and bable-trunsform-runtime like me, you can set:

"sourceType": "unambiguous",
Contributor

flyyang commented Sep 7, 2018

Thanks @loganfsmyth

Short answer。

If you are using babel 7 and bable-trunsform-runtime like me, you can set:

"sourceType": "unambiguous",
@tomsoderlund

This comment has been minimized.

Show comment
Hide comment
@tomsoderlund

tomsoderlund Sep 19, 2018

I solved this issue by replacing import with require in my code.

tomsoderlund commented Sep 19, 2018

I solved this issue by replacing import with require in my code.

ulivz added a commit to vuejs/vuepress that referenced this issue Sep 27, 2018

fix($core): Cannot assign to read only property 'exports' of object (c…
…lose: #869)

This is weird issue of webpack. since ClientComputedMixin was used both in server and client side,
client es module will import this commonJS module, it should work but webpack throw error: 'Uncaught
TypeError: Cannot assign to read only property 'exports' of object '#<Object>''. related issue:
webpack/webpack#4039
@chrisdothtml

This comment has been minimized.

Show comment
Hide comment
@chrisdothtml

chrisdothtml Sep 27, 2018

You can't mix import and module.exports

@sokra how difficult would it be to add a webpack compile error for this case? Seems there's room for a clearer explanation

chrisdothtml commented Sep 27, 2018

You can't mix import and module.exports

@sokra how difficult would it be to add a webpack compile error for this case? Seems there's room for a clearer explanation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment