【问题标题】:Using Webpack on an existing angular 1.x application在现有的 Angular 1.x 应用程序上使用 Webpack
【发布时间】:2017-06-13 13:37:54
【问题描述】:

我有一个现有的、非常大的 Angular 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如何知道要加载哪些文件?给定入口点它做了什么。

谢谢

【问题讨论】:

  • 是否需要将所有文件转换为 ES6 模块导入/导出语法? - 不一定是导入/导出,可以是带有 require 的 CJS 模块,但是可以. 当旧的 Angular 语法时,Webpack 如何知道要加载哪些文件 - 它不知道。这是你的责任。
  • 这意味着根文件应该包含应用程序运行所需的所有模块,这意味着不是根文件的所有其他文件都必须位于与根文件不同的模块中,并且根文件应该包含它(不一定直接,而是分层)?
  • 你是指Angular模块还是'modules'的JS模块?
  • Angular 模块
  • 当每个文件(JS 模块)有 1 个 Angular 模块时效果最好。参见例如 stackoverflow.com/a/43858286/3731501 。否则,您需要先定义 Angular 模块,然后才能导入与 angular.module('app') 一起使用它的文件。这破坏了模块封装。

标签: angularjs webpack


【解决方案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;

如果您还有任何疑问,请告诉我。我仍然记得我必须努力让事情顺利进行。很乐意为您提供帮助!

【讨论】:

    【解决方案2】:

    把它放在这里以防其他人遇到这个问题。本质上,webpack 试图做的是构建一个依赖图。这意味着有一个入口点,然后 webpack 将查看该文件并通过查看其中是否有任何导入或 require 语句来查看它所依赖的内容。然后它将前往依赖文件并捆绑该文件,同时寻找更多的依赖项等等。通过这种方式,它知道哪些东西需要在其他人之前加载。 听起来您没有更改源代码来导入或需要任何模块的依赖项,因此 Webpack 只是构建了您指向它的一个文件,而不是应用程序的所有文件。

    假设 ModuleA 依赖于 ModuleB 和 ModuleC。 在 ModuleA.js 中,您将导入(或需要)moduleB 以及 ModuleC。 在 ModuleB 和 ModuleC 中,您都需要导出它们并确保从模块中导出 .name 属性,因为 AngularJS 需要字符串作为其依赖项。 将 AngularJS 与 Webpack 一起使用的棘手之处在于,Angular 有自己的模块系统,它不同于 commonJS 模式或 ESModules,所以它的组合有点奇怪。

    Softvar 的上述解决方案有效,因为他告诉 webpack 在 resolve 属性下定义他的模块时要捆绑什么。如果您的所有子模块都被导出,另一种将您的所有 Angular 文件捆绑到一个父模块中导出的解决方案是这样的,其中文件是 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;
    

    【讨论】:

      猜你喜欢
      • 2017-07-23
      • 1970-01-01
      • 2016-10-02
      • 2017-06-03
      • 1970-01-01
      • 2017-12-13
      • 2016-02-01
      • 1970-01-01
      • 2017-09-21
      相关资源
      最近更新 更多