Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

cannot use angular-moment under webpack #108

Closed
kimcmich opened this issue Jan 22, 2015 · 22 comments
Closed

cannot use angular-moment under webpack #108

kimcmich opened this issue Jan 22, 2015 · 22 comments
Assignees
Milestone

Comments

@kimcmich
Copy link

I'm running an angular app under webpack-dev-server that includes moment and angular moment. My basic config file stars as:

var app;

require("jquery");
require("angular");
require("ui_router");
require("facebook");
require("bootstrap_css");
require("index_scss");
require("ui_bootstrap");
require("angular_mocks");
require("angular_sanitize");
require("moment");
require("angular_moment");

mockApp = angular.module('mockApp', ['sp.app', 'ngMockE2E'])
.run (['$httpBackend',
    function($httpBackend) {
        server_url = 'https://dev.sharepractice.com';
        $httpBackend.whenGET(server_url + '/api/v1/specialties_list')
            .respond({
                results: ['Voodoo', 'Acupuncture and Oriental Medicine', 'Addiction Medicine', 'Functional Medicine']
            });
        $httpBackend.whenGET(/.*/).passThrough();
        $httpBackend.whenPOST(/.*/).passThrough();
    }
]);

app = angular.module("sp.app", ['ui.router', 'ui.bootstrap', 'facebook', 'mockApp', 'ngSanitize', 'angularMoment'])

I get a javascript error when angular-moment loads that "angular.moment" is not a function.

I investigated this and found that, for some reason, when angular-moment is intializing, the passed in value for angular is an empty object (not null/undefined but an empty object). I fixed the problem in my local source for angular-moment by adding a check for an empty angular object at which point I assign angular the value of window.angular (which does exist). This fixes the issue, but, as is, angular-moment will not work with my app otherwise...

My modification:
before the line #20 in angular-moment.js v0.9.0, I insert this block

var angularAvailable = false;
for (prop in angular) {
    angularAvailable = true;
}

if (!angularAvailable) {
    angular = window.angular;
}
ryanray added a commit to zanebenefits/angular-moment that referenced this issue Mar 27, 2015
@kumarharsh
Copy link

You can make the module work by using this webpack config in your source code:

function absPath(_path) {
  return path.join(__dirname, _path);
}

"angular-moment": {path: absPath('node_modules/angular-moment/angular-moment.js'), imports: ['define=>false', 'angular', 'moment']},

and using webpack's imports-loader loader. The trick is setting the define as false, so that the broken define is not run, instead the module.exports part is run.

@cbfx
Copy link

cbfx commented Sep 2, 2015

@kumarharsh thanks for the help on this issue. i'm new to webpack but am running into this issue, unfortunately. could you give me an example of where the 'angular-moment' key needs to go in a config file and a little explanation on it? thanks in advance.

@cbfx
Copy link

cbfx commented Sep 2, 2015

@kumarharsh i've resolved the issue on my end by adding this:

module: {
  loaders: [
    ...
    {test: /[\/]angular\.js$/, loader: "exports?angular"}
  ]
}

@urish
Copy link
Owner

urish commented Sep 15, 2015

Should be fixed here:

angularMoment(require('angular'), require('moment'));

Please check and report back!

Thanks :)

@urish urish closed this as completed Sep 15, 2015
@urish urish added this to the 1.0.0 milestone Sep 15, 2015
@urish urish self-assigned this Sep 15, 2015
@voor
Copy link

voor commented Sep 30, 2015

Webpack still hits the first part:

if (typeof define === 'function' && define.amd) {
        define(['angular', 'moment'], angularMoment);

And breaks with the same error message of Uncaught TypeError: angular.module is not a function

The compiled WEBPACK shows this:

if (true) {
            !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(3), __webpack_require__(26)], __WEBPACK_AMD_DEFINE_FACTORY__ = (angularMoment), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));

Which means it's definitely executing the first function instead of the second.

@fvelosa
Copy link

fvelosa commented Oct 25, 2015

Hi, I also get the same error even after upgrading to 1.0.0-beta.2 `Uncaught TypeError: angular.module is not a function.

@luisfontes
Copy link

Same here on 1.0.0-beta.2

@urish
Copy link
Owner

urish commented Oct 31, 2015

Alright, I want to get this fixed for 1.0.0-beta.3.

Can you please check whether switching the order of the if statements helps?

i.e.

if (typeof module !== 'undefined' && module && module.exports) {
    angularMoment(require('angular'), require('moment'));
    module.exports = 'angularMoment';
} else if (typeof define === 'function' && define.amd) {
    define(['angular', 'moment'], angularMoment);
} else {
     angularMoment(angular, (typeof global !== 'undefined' ? global : window).moment);
}

@luisfontes
Copy link

I've pasted your code and got the same error. I managed to get it working with this if block:

    if (typeof module !== 'undefined' && module && module.exports) {
        angularMoment(angular, moment);
        module.exports = 'angularMoment';
    } else if (typeof define === 'function' && define.amd) {
        define(['angular', 'moment'], angularMoment);
    } else {
        angularMoment(angular, (typeof global !== 'undefined' ? global : window).moment);
    }

@urish urish reopened this Nov 1, 2015
@urish
Copy link
Owner

urish commented Nov 7, 2015

@luisfontes thanks a million! can you please paste your webpack configuration? or even better, make a small gist / github repo that reproduces this?

Thanks!

aaronroberson added a commit to aaronroberson/angular-moment that referenced this issue Nov 20, 2015
Here is my webpack.config.js file if it helps:

```
{
    entry: {
      app: './src/app.js'
    },
    output: {
      filename: 'app.js'
    },
    watch: watch,
    devtool: (process.env.NODE_ENV === 'production') ? 'source-map' : 'inline-source-map',
    module: {
      preLoaders: [{test: /\.js$/, exclude: [/node_modules/, /bower_components/], loader: 'jshint'}],
      loaders: [
        {test: /\.js$/, exclude: [/node_modules/, /bower_components/], loader: 'babel', query: {
          // https://github.com/babel/babel-loader#options
          cacheDirectory: true,
          presets: ['es2015', 'stage-0', 'stage-1', 'stage-2'],
          plugins: ['transform-es2015-modules-commonjs']
        }},
        {test: /\.css$/, loader: 'style!css!postcss'},
        {test: /\.json$/, exclude: [/node_modules/, /bower_components/], loader: 'json'},
        {test: /[\/]angular\.js$/, exclude: [/bower_components/], loader: 'exports?angular'}
      ]
    },
    postcss: [autoprefixer({ browsers: ['last 2 version'] })],
    plugins: [
      new BowerWebpackPlugin({
        exclude: [
          /.*angular*/,
          /.*angular-cookies*/,
          /.*angular-sanitize*/,
          /.*angular-resource*/,
          /.*angular-messages*/,
          /.*angular-translate*/,
          /.*angular-touch*/,
          /.*angular-mocks*/,
          /.*jquery*/,
          /.*bootstrap-sass-official\/.*\.js/,
          /.*bootstrap\.css/,
          /.*awesome-bootstrap-checkbox*/,
          /.*font-awesome*/,
          /.*\.less/
        ],
        searchResolveModulesDirectories: false
      }),
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery',
        moment: 'moment'
      }),
      new webpack.DefinePlugin({
        ENV_TEST: (JSON.stringify(process.env.NODE_ENV) === 'test') ? true : false
      }),
      new webpack.DefinePlugin({
        APP_VERSION: JSON.stringify(require('./package.json').version)
      })
    ],
    resolve: {
      root: path.resolve('./src'),
      modulesDirectories: ['node_modules'],
      extensions: ['', '.js', '.json', '.css']
    }
  };
```

Resolves urish#108
aaronroberson added a commit to aaronroberson/angular-moment that referenced this issue Nov 20, 2015
Fix the module export for webpack

Resolves urish#108
@laggingreflex
Copy link

Facing this exact same issue in other angular modules as well (angular-moment, angular-storage, angular-translate), even angular itself! All errors are on the line where Webpack replaces the define statement (as stated by @voor above). This is my webpack.config. I've installed all modules via npm and require them in es5 syntax.

@pavel06081991
Copy link

have the same problem.

@timc13
Copy link

timc13 commented Dec 23, 2015

+1

@vogloblinsky
Copy link

+1
Unit testing using theintern fails with define block.

@ace-han
Copy link

ace-han commented Feb 15, 2016

+1

2 similar comments
@aaweb
Copy link

aaweb commented Feb 29, 2016

+1

@readme42
Copy link

readme42 commented Mar 1, 2016

+1

@Mikaeru001
Copy link

Got it working by applying exports-loader to angular.js file. It is the same solution as @cbfx has suggested. No need to inject define=>false with imports-loader.

webpack.config.js:

...
module: {
  loaders: [
    { test: path.resolve('./app/bower_components/angular/angular.js'), loader: 'exports?angular'},
    ...
  ]
}
...

@gregorskii
Copy link

This is not working for me regardless of the workarounds in this ticket.

I am not using loaders. I am using the loaders directly in the require statement:

require('exports?$!exports?jQuery!expose?$!expose?jQuery!jquery');
require('exports?angular!angular');
require('imports?angular!angular-moment');

I have tried the loaders in the webpack config, I have also tried with and without imports?angular on angular-moment.

The project I am working on is using a pretty old version of angular. I have also tried updating angular and that does not work either.

It is currently using Angular 1.2.20, I would prefer to not have to introduce other breaking changes. But I have tried updating all of my bower and npm packages completely. This did not help either.

I am currently using these packages:

bower:

"dependencies": {
    "angular": "~1.2.20",
    "jquery": "~2.1.1",
    "angular-resource": "~1.2.20",
    "angular-cookies": "~1.2.20",
    "angular-sanitize": "~1.2.20",
    "angular-route": "~1.2.20",
    "angular-underscore-module": "~1.0.3",
    "underscore": "~1.6.0",
    "ngstorage": "~0.3.0",
    "angular-bootstrap": "~0.11.0",
    "angular-ui-router": "~0.2.11",
    "angular-upload": "~1.0.11",
    "bootstrap-sass-official": "~3.2.0",
    "jasny-bootstrap": "3.2.0-beta.1",
    "angular-chosen-localytics": "~1.0.6",
    "tinymce": "^4.3.8"
  },
  "devDependencies": {
    "angular-mocks": "~1.2.20",
    "angular-scenario": "~1.2.20"
  }

NPM:

  "devDependencies": {
    "bower-webpack-plugin": "^0.1.9",
    "browser-sync": "^2.9.1",
    "css-loader": "^0.23.1",
    "del": "^2.0.1",
    "exports-loader": "^0.6.3",
    "expose-loader": "^0.7.1",
    "file-loader": "^0.8.5",
    "gulp": "^3.9.0",
    "gulp-autoprefixer": "^3.0.0",
    "gulp-changed": "^1.3.0",
    "gulp-concat-util": "^0.5.5",
    "gulp-eslint": "^2.0.0",
    "gulp-if": "^2.0.0",
    "gulp-minify-css": "^1.2.1",
    "gulp-notify": "^2.2.0",
    "gulp-plumber": "^1.0.1",
    "gulp-rename": "^1.2.2",
    "gulp-replace": "^0.5.4",
    "gulp-sass": "^2.0.4",
    "gulp-sequence": "^0.4.1",
    "gulp-shopify-upload": "^2.0.0",
    "gulp-sourcemaps": "^1.5.2",
    "gulp-uglify": "^1.5.3",
    "gulp-debug": "^2.1.2",
    "gulp-util": "^3.0.6",
    "gulp-watch": "^4.3.5",
    "jsdoc": "^3.3.2",
    "jsonfile": "^2.2.1",
    "lodash": "^4.5.1",
    "ng-annotate-webpack-plugin": "^0.1.2",
    "pretty-hrtime": "^1.0.2",
    "raw-loader": "^0.5.1",
    "require-dir": "^0.3.0",
    "style-loader": "^0.13.0",
    "through2": "^2.0.0",
    "vinyl-named": "^1.1.0",
    "webpack": "^1.12.14",
    "webpack-stream": "^3.1.0"
  },
  "dependencies": {
    "angular-moment": "^1.0.0-beta.5",
    "imports-loader": "^0.6.5",
    "moment": "^2.12.0",
    "phoneformat": "0.0.7"
  }

@gregorskii
Copy link

Update:

This is the only config that worked for me (only relative parts shown):

loaders: [
    {test: /[\/]angular\.js$/, exclude: ['/bower_components/'], loader: 'exports?angular'},
]
new webpack.ProvidePlugin({
    '$': 'jquery',
    'jQuery': 'jquery',
    'window.jQuery': 'jquery',
    'moment': 'moment'
})

@enricop89
Copy link

This is not working for me regardless of the commit https://github.com/urish/angular-moment/commit/517f42fb2fbbfe0823cc7d8e667c4cce5a6cb317
Is there a working configuration for this issue?

@adeptues
Copy link

adeptues commented Nov 18, 2016

This is still happening for me using version 1.0.0 the following code snippet appears to be the problem

if (true) {
            !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(43), __webpack_require__(49)], __WEBPACK_AMD_DEFINE_FACTORY__ = (angularMoment), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
        } else if (typeof module !== 'undefined' && module && module.exports && (typeof require === 'function')) {
            module.exports = angularMoment(require('angular'), require('moment'));
        } else {
            angularMoment(angular, (typeof global !== 'undefined' ? global : window).moment);
        }

Not sure why its always if(true) then with the webpack generated stuff

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