noppa / ng-hot-reload

Hot reloading for AngularJS apps.
MIT License
43 stars 8 forks source link

Module parse failed: 'import' and 'export' may only appear at the top level #13

Closed YonathanB closed 5 years ago

YonathanB commented 5 years ago

I can run your example, but with my current project it doesn't work.

I tried to do exactly the same config as you have in your webpack example, but it seems I'm missing something.

When adding the ng-hot-reload-loader like this:

                {
                    test: /\.js$/,
                    use: ['ng-hot-reload-loader', 'babel-loader'],// TODO , 'eslint-loader'
                    exclude: /node_modules/
                }

Webpack fail with following error:

Module parse failed: 'import' and 'export' may only appear at the top level (15:6) You may need an appropriate loader to handle this file type. (function() {/ ng-hot-reload-loader end/
  import 'angular/angular';

| import $ngAnimate from 'angular-animate';

Can you assist?

noppa commented 5 years ago

What's your babelrc like? Looks like it's not transforming the import statements to commonjs requires. You might be missing this modules: commonjs line.

YonathanB commented 5 years ago

I "copy/paste" the same .babelrc has you have. I also have the same packages in NPM

"devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
    "@babel/preset-env": "^7.2.3",
    "@lgrignon/zip.js": "^1.0.1",
    "angular-mocks": "^1.7.5",
    "babel-loader": "^8.0.4",
    "babel-plugin-angularjs-annotate": "^0.9.0",
    "babel-polyfill": "^6.26.0",
    "clean-webpack-plugin": "^1.0.0",
    "css-loader": "^1.0.0",
    "eslint": "^5.10.0",
    "event-stream": "^4.0.1",
    "file-loader": "^1.1.4",
    "gulp": "^3.9.1",
    "gulp-angular-gettext": "^2.2.0",
    "gulp-bower": "0.0.13",
    "gulp-chmod": "^2.0.0",
    "gulp-clean-css": "^3.7.0",
    "gulp-concat": "^2.6.1",
    "gulp-flatten": "^0.3.1",
    "gulp-iconfont": "^9.1.0",
    "gulp-iconfont-css": "^2.1.0",
    "gulp-inject": "^4.2.0",
    "gulp-inject-string": "^1.1.0",
    "gulp-less": "^3.3.2",
    "gulp-ng-annotate": "^2.1.0",
    "gulp-rename": "^1.2.2",
    "gulp-replace": "^0.6.1",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-spreadsheet2json": "^1.0.6",
    "gulp-uglify": "^3.0.0",
    "gulp-useref": "^3.1.2",
    "gulp-zip": "^4.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "imports-loader": "^0.8.0",
    "jasmine": "^2",
    "jasmine-core": "^2",
    "karma": "^1.5.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-coverage": "^1.1.1",
    "karma-jasmine": "^1",
    "karma-junit-reporter": "^1.2.0",
    "less-loader": "^4.1.0",
    "main-bower-files": "^2.13.1",
    "mini-css-extract-plugin": "^0.4.4",
    "ng-annotate": "^1.2.2",
    "ng-annotate-loader": "^0.6.1",
    "ng-hot-reload-loader": "^2.0.3",
    "ng-hot-reload-standalone": "^2.0.3",
    "path-exists": "^3.0.0",
    "resolve-url-loader": "^3.0.0",
    "run-sequence": "^2.1.0",
    "speed-measure-webpack-plugin": "^1.2.3",
    "style-loader": "^0.23.1",
    "terser-webpack-plugin": "^1.1.0",
    "webpack": "^4.27.1",
    "webpack-bundle-analyzer": "^3.0.3",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10",
    "webpack-jquery-ui": "^2.0.1",
    "webpack-manifest-plugin": "^2.0.4",
    "webpack-md5-hash": "^0.0.6",
    "webpack-php-loader": "^0.5.0"
  },
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": "commonjs"
      }
    ]
  ]
}
noppa commented 5 years ago

That's weird. Do you happen to have the code in github or somewhere I could try it out?

Many of those package.json dependencies aren't required, btw, since you are probably using just webpack and not gulp. The loader works with both so that's why the demo project has both webpack and gulp stuff in it. But I guess it makes sense to just have them all for now and trim those down when you get things working.

YonathanB commented 5 years ago

When I'm running (without ng-hot-reload-loader )

{
                    test: /\.js$/,
                    loader: 'babel-loader'
                    exclude: /node_modules/
                }

It works good and my babel is transpiling my code I wanted.

Source code isn't on github and I can't publish it (private). Project needs all that dependencies.

Do you think it can come from one of them?

noppa commented 5 years ago

I made a small test repo for this issue here: noppa/ng-hot-reload-issue-13-test, but can't really reproduce the problem. Everything seems to work fine there.

noppa commented 5 years ago

I get pretty much the same error as you if I remove the babelrc file or the "modules" option, which makes me think that the webpack loader probably isn't using the correct babelrc file for some reason.

YonathanB commented 5 years ago

Ok, thank you for answering 👍 . I fixed that issue by adding the following:

{
   loader: 'ng-hot-reload-loader'
 },{
      loader: 'babel-loader',
      options: {
        ...JSON.parse(fs.readFileSync(path.resolve(__dirname, './.babelrc'))),
}

As you said:

webpack loader probably isn't using the correct babelrc file

I needed to add that option to babel-loader in order to tell him where is the .babelrc file (don't know why because both my webpack.config and .babelrc in same directory).

Anyway, I don't have the issue but is not refreshing the app. I get warnings:

log.js:26 Ignored an update to unaccepted module ../../../../../../WebApplication/Client/application/components/dashboard/location-status/location-status.html -> ../../../../../../Dashboard/WebApplication/Client/application/components/dashboard/location-status/location-status.component.js -> ../../../../../../WebApplication/Client/application/components/dashboard/dashboard.module.js -> ../../../../../../WebApplication/Client/application/app.js -> ../../../../../../WebApplication/Client/src/index.js -> 1 push.../../../../../../WebApplication/Client/application/node_modules/webpack/hot/log.js.module.exports @ log.js:26 onUnaccepted @ only-dev-server.js:31 hotApply @ bootstrap:522 (anonymous) @ only-dev-server.js:26 Promise.then (async) check @ only-dev-server.js:15 (anonymous) @ only-dev-server.js:91 push.../../../../../../WebApplication/Client/application/node_modules/events/events.js.EventEmitter.emit @ events.js:81 reloadApp @ client?7afc:227 ok @ client?7afc:140 onmessage @ socket.js:41 EventTarget.dispatchEvent @ sockjs.js:170 (anonymous) @ sockjs.js:887 SockJS._transportMessage @ sockjs.js:885 EventEmitter.emit @ sockjs.js:86 WebSocketTransport.ws.onmessage @ sockjs.js:2961

I see somewhere to add in the entry point:

if (module.hot) {
    module.hot.accept();
}

Warning disappear but still doesn't refresh the page

noppa commented 5 years ago

Have you made progress on this?
I haven't had much time to look into this and it's a bit difficult to say much about the problem without some kind of reproducible example.

I see somewhere to add in the entry point:

That's basically what this library does, it's not something you should need to do manually.

YonathanB commented 5 years ago

@noppa , Ok... so first thing was to give the path to //babelrc in webpack.config.

Then I had a probem with babel because it set "use strict"before all files. It was a problem for me because I have a lot of global variables in my project (I know, that's not a good practice).

My javascript file is beeing updated, but it seems that angular needs to be refreshed....

I see that your loader is decorating my code. at the end of each file I can see:

 (function() {
      if (module.hot && angular.__ngHotReload$didRegisterProviders) {
        module.hot.accept(function(err) {
          if (err) {
            console.error(err);
          }
        });
      }
    })();

angular.__ngHotReload$didRegisterProviders is false for me so function is not beeing called, can you please help me?

noppa commented 5 years ago

angular.__ngHotReload$didRegisterProviders is false for me

That should happen if the file that you modified doesn't have any calls to

angular.module(..).directive( .. )

or .controller(..) or .component(..). Is that the case?

YonathanB commented 5 years ago

I make it works with one component. The code was in a IIFE and it seems like a probem. I had:

import root from './rootPath'
(function () {
angular.module('mainModule').component('root', root)
})()

If I remove the IIFE, it works.

My other code isn't called directly into angular.module(..).

I have a component directory which is a module:

export default require('angular')
    .module('myComponents', ['someDIs'])
    .component('component1', component1)
    .component('component2', component2)
    .component('component3', component3)
.name

Then I import that module into my main module and use it in ui-router

import myComponents from './myComponentsPath';
angular.module('mainModule', [  'myComponents',...])

 .state('main.dashboard.locations', {
                    url: '/a-path',
                    component: 'component1'
                })

It can works?

noppa commented 5 years ago

I think the problem might be that require('angular') call. This library wraps your code with something like

(function(angular) {
 ...your code...
})(...)

The idea being that your code will then use that "fake" angular that this library has modified to support hot reloading.

Try using the global variable that angular adds, i.e.

import 'angular'
// ^^^ This is here just to make sure that angular is imported in the project.
// Angular will automatically add global "angular" variable.

export default angular
    .module('myComponents', ['someDIs'])
    .component('component1', component1)
    .component('component2', component2)
    .component('component3', component3)
    .name
YonathanB commented 5 years ago

YOU SAVE MY LIFE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

how can I thank you? Really :)