使用webpack导入angularjs的最佳实践是什么?

52

如何将Webpack和AngularJS结合使用?如何处理模板加载和按需获取资源?

非常感谢提供一个针对此目的编写良好的webpack.config.js文件的示例。

此处显示的所有代码片段都可在这个GitHub存储库中访问。代码已经大量改编自这个packetloop git存储库

webpack.config.json

var path = require('path');
var ResolverPlugin = require("webpack/lib/ResolverPlugin");

var config = {
  context: __dirname,
  entry: ['webpack/hot/dev-server', './app/app.js'],
  output: {
    path: './build',
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: /\.css$/,
      loader: "style!css-loader"
    }, {
      test: /\.scss$/,
      loader: "style!css!sass?outputStyle=expanded"
    }, {
      test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/,
      loader: "file"
    }, {
      test: /\.html$/,
      loader: "ngtemplate?relativeTo=" + path.join(__dirname, 'app/') + "!raw"
    }]
  },
  // Let webpack know where the module folders are for bower and node_modules
  // This lets you write things like - require('bower/<plugin>') anywhere in your code base
  resolve: {
    modulesDirectories: ['node_modules', 'lib/bower_components'],
    alias: {
      'npm': __dirname + '/node_modules',
      'vendor': __dirname + '/app/vendor/',
      'bower': __dirname + '/lib/bower_components'
    }
  },
  plugins: [
    // This is to help webpack know that it has to load the js file in bower.json#main
    new ResolverPlugin(
      new ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
    )
  ]
};

module.exports = config;

将AngularJS导入到主app.js中,您需要执行以下操作:

app/vendor/angular.js

'use strict';

if (!global.window.angular) {
  require('bower/angular/angular');
}
var angular = global.window.angular;
module.exports = angular;

然后可以像这样在app.js中使用它:

app.js

...
var angular = require('vendor/angular');

// Declare app level module
var app = angular.module('myApp', []);

...

以下内容是否正确?有没有更简单的方法?我看到过一些(并不是很多)列出了另一种方法的帖子。

来自这个Reddit帖子的评论

// Add to webpack.config.js#module#loaders array
    {
      test: /[\/]angular\.js$/,
      loader: "exports?angular"
    }

目前还有另一个插件正在开发中,位于stackfull/angular-seed。它似乎朝着正确的方向发展,但目前使用起来非常困难。

Webpack非常棒,但缺乏文档和示例使其难以上手。


1
Angular本身可以与webpack完美配合使用 - var angular = require('angular')。您还可以通过每个模块上的name属性来要求您的模块 - var myModule = require('./myModule'); angular.module('foo', [myModule.name])。有一些例外情况 - ui router是一个显著的例子,它不导出模块对象,而是导出模块名称本身。 - Dan
这也可能是一个不错的起点。它帮助了我。https://egghead.io/lessons/angularjs-angular-with-webpack-introduction - michaelgmcd
1
Angular在没有app/vendor/angular.js的情况下,无法直接使用语法:var angular = require('angular')。如果您使用exports loader并使用Angular,则可以在没有vendor/angular.js的情况下使其正常工作。此外,请注意您的依赖项应该是npm依赖项。Bower依赖项将无法与exports loader一起使用。 - randominstanceOfLivingThing
2个回答

13
您可以在需要的所有模块(文件)中使用require引入Angular。我有一个GitHub代码库,其中提供了如何实现此操作的示例(同时使用webpack进行构建)。在示例中使用了ES6的导入语法,但这并不重要,您也可以使用标准的require()语法。
示例:
import 'bootstrap/dist/css/bootstrap.min.css';
import './app.css';

import bootstrap from 'bootstrap';

import angular from 'angular';
import uirouter from 'angular-ui-router';

import { routing} from './app.config';

import common from './common/common.module';

import featureA from './feature-a/feature-a.module';
import featureB from './feature-b/feature-b.module';

const app = angular
    .module('app', [uirouter, common, featureA, featureB])
    .config(routing);

1
在 Angular 模块依赖项中,不应该包含 uirouter.name 等内容吗? - Dmitri Zaitsev
1
它的工作原理就是这样,查看实际示例:https://github.com/tomastrajan/angular-js-es6-testing-example/blob/master/src/feature-b/feature-b.module.js - tomastrajan

7
我正在使用Angular+Flux和Webpack开始编程,或许我能帮你解决一些问题。
基本上,我会通过NPM安装所有内容,它具有模块导出系统,所以它的工作就像没有任何问题。(你可以使用export-loader,但如果不需要,为什么要使用呢。)
我的webpack.config.js看起来像这样:
var webpack           = require('webpack');
var path              = require('path');
var HtmlWebpackPlugin = require("html-webpack-plugin");

var nodeModulesDir = path.resolve(__dirname, './node_modules');

// Some of my dependencies that I want
// to skip from building in DEV environment
var deps = [
  'angular/angular.min.js',
  ...
];

var config = {
  context: path.resolve(__dirname, './app'),

  entry: ['webpack/hot/dev-server', './main.js'],

  resolve: {
    alias: {}
  },

  output: {
    path: path.resolve(__dirname, './build'),
    filename: 'bundle.js'
  },

  // This one I am using to define test dependencies
  // directly in the modules
  plugins: [
    new webpack.DefinePlugin({
      ON_TEST: process.env.NODE_ENV === 'test'
    })
  ],

  module: {
    preLoaders: [
      {test: /\.coffee$/, loader: "coffeelint", exclude: [nodeModulesDir]}
    ],
    loaders: [
      {test: /\.js$/, loader: 'ng-annotate', exclude: [nodeModulesDir]},
      {test: /\.coffee$/, loader: 'coffee', exclude: [nodeModulesDir]},
        ...
    ],
    noParse: []
  },

  devtool: 'source-map'
};

if (process.env.NODE_ENV === 'production') {
  config.entry = {
    app: path.resolve(__dirname, './app/main.js'),
     vendors: ['angular']
  };
  // config.output.path = path.resolve(__dirname, './dist');
 config.output = {
   path: path.resolve(__dirname, "./dist"),
  filename: "app.[hash].js",
  hash: true
 };
 config.plugins.push(new webpack.optimize.UglifyJsPlugin());
 config.plugins.push(new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.[hash].js'));
 config.plugins.push(new HtmlWebpackPlugin({
   title: 'myApp',
   template: path.resolve(__dirname, './app/index.html'),
   inject: 'body'
 }));

 delete config.devtool;


}
  else {
    deps.forEach(function (dep) {
      var depPath = path.resolve(nodeModulesDir, dep);
      config.resolve.alias[dep.split(path.sep)[0]] = depPath;
      config.module.noParse.push(depPath);
    });
  }
module.exports = config;

我的 main.js 文件看起来像这样:

var angular = require('angular');

if(ON_TEST) {
  require('angular-mocks/angular-mocks');
}

require('./index.coffee');

index.coffee 包含主要的 Angular 模块:

ngModule = angular.module 'myApp', []

require('./directive/example.coffee')(ngModule)

这太棒了。恭喜你。 这个代码是开源的吗?我想看一下这个项目,我在使用Webpack时遇到了一些问题。 :) - ridermansb
@Kamil,你有没有搞定那个repo?我真的很想看看它。至少,你能给我展示一下./directive/example.coffee文件大致是什么样子吗? - anbiniyar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接