在现有的角度1.x应用程序上使用Webpack

时间:2017-06-13 13:37:55

标签: angularjs webpack

我有一个现有的,非常大的角度1.x应用程序,它运行今天的ES5代码。 几乎所有应用程序都在同一模块上运行。我的主模块在文件“dashboardApp.js”中定义。

我想开始将ES6与每个组件的模块一起使用,因为应用程序是组件结构化的。为了让它在开发中运行,我想开始使用Webpack。

我尝试添加Webpack,因此我添加了所有必需的npm依赖项并添加了以下webpack.config.js

var webpack = require('webpack');
module.exports = {
  entry: '../app/dashboardApp.js',
  output:{
     path: __dirname + '/../dst/dist',
     filename: 'my.bundle.js'
  },
  module:{
    rules: [{
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /(node_modules|bower_components)/
    }]
}
};

另外,我在package.json中添加了以下属性:

"scripts": {
    "build": "webpack --config webpack.config.js"
  },

并且能够成功运行构建并创建my.bundle.js。但是,当尝试仅使用my.bundle.js脚本加载应用程序时,我得到了一个例外:

Uncaught Error: [$injector:modulerr] Failed to instantiate module dashboardApp due to:
Error: [$injector:unpr] Unknown provider: myConsts

myConsts是一个角度常量,在使用Webpack之前通过加载脚本来包含,因此我的问题是:

为了将用于显式加载所有脚本的现有angular 1.x应用程序转换为一个Webpack生成的脚本应用程序,需要什么?我需要在所有文件中进行哪些更改,这些更改都在同一模块上定义,以便包含在生成的文件中。我知道webpack是一个模块捆绑器,但我不了解我需要做什么才能使旧的应用程序与Webpack一起工作。我是否需要将所有文件转换为ES6模块导入/导出语法?当旧的角度语法(1个控制器/服务/常量...每个文件全部在同一个模块上)时,Webpack如何知道要加载哪些文件?考虑到切入点,它做了什么。

由于

2 个答案:

答案 0 :(得分:1)

如果您的应用使用requirejs,那么您可以使用webpack2实现它。只需使用规则和别名正确配置它。我的应用程序也使用requirejs,经过多次努力,我成功地设法用webpack2替换了Grunt。

以下是webpack.config.js文件:

const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

let basePath = path.join(__dirname, '/');

let config = {
  // Entry, file to be bundled
  entry: {
    'main': basePath +  '/src/main.js',
  },
  devtool: 'source-map',
  output: {
    // Output directory
    path: basePath +  '/dist/',
    library: '[name]',
    // [hash:6] with add a SHA based on file changes if the env is build
    filename: env === EnvEnum.BUILD ? '[name]-[hash:6].min.js' : '[name].min.js',
    libraryTarget: 'amd',
    umdNamedDefine: true
  },
  module: {
    rules: [{
      test: /(\.js)$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        // babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
        loader: 'babel-loader',
        options: {
          presets: ['es2015'],
          plugins: []
        }
      }
    }, { test: /jQuery/, loader: 'expose-loader?$' }, 
  { test: /application/, loader: 'expose-loader?application' },
  { test: /base64/, loader: 'exports-loader?Base64' }
    ]
  },
  resolve: {
    alias: {
        'jQuery': 'bower_components/jquery/dist/jquery.min',
        'application': 'main',
        'base64': 'vendor/base64'
    },
    modules: [
      // Files path which will be referenced while bundling
      'src/**/*.js',
      'src/bower_components',
      path.resolve('./src')
    ],
    extensions: ['.js'] // File types
  },
  plugins: [

  ]
};

module.exports = config;

如果您有任何疑问,请与我们联系。我还记得我有多努力让事情发挥作用。非常乐意为您提供帮助!

答案 1 :(得分:0)

将其放在此处,以防其他人遇到此问题。从本质上讲,webpack试图做的是建立一个依赖图。意味着有一个入口点,然后webpack将查看该文件并通过查看其中是否有任何导入或require语句来查看其依赖项。然后它将移动到依赖项文件并捆绑该文件,同时还要查找更多依赖项,依此类推。这样,它知道在其他事物之前需要加载什么。 听起来您好像没有更改源代码即可导入或不需要模块的任何依赖项,因此Webpack只是构建了您指向它的一个文件,而不是应用程序的所有文件。

可以说ModuleA取决于ModuleB和ModuleC。 在ModuleA.js中,您将导入(或要求)moduleB和ModuleC。 在ModuleB和ModuleC中,都需要导出它们,并确保从模块中导出.name属性,因为AngularJS希望使用字符串作为其依赖项。 将AngularJS与Webpack一起使用时,棘手的事情是Angular拥有自己的Module系统,该系统与commonJS模式或ESModules不同,因此它的组合有点奇怪。

Softvar的上述解决方案之所以有效,是因为他告诉webpack在resolve属性下定义模块时要捆绑的内容。如果所有子模块都已导出,则将所有角度文件捆绑到一个父模块中进行导出的另一种解决方案是这样的,其中文件为index.js,而webpack在此处作为其入口点:

const modules = [];

function importAll(webpackContext) {
  // the webpackContext parameter is a function returned after invoking require.context() that has
  // access to all of the resolved paths defined in the require.context call.

  // The keys will be an array of all of the resolved module paths returned from the initial
  // require.context invocation within the importAll invocation a number of lines below this declaration.
  webpackContext.keys()

  // this will fetch each module itself and give us access to all of the exports from that module.
  // Since we are exporting the angular modules as the default export from all of our index files,
  // we are just pushing the default property into the modules array. In this case the default property
  // is the string name of the angular module.
    .forEach(modulePath => modules.push( webpackContext(modulePath).default) );
}

// recurse through all sub directories in ./src and find the path for each index.js file.
importAll(require.context("./src/", true, /index\.js$/));

// take all of the module's name strings and spread them out as module dependencies.
// export the single module all glued together.
export default angular.module("YOUR_MODULE_NAME", [...modules]).name;