【问题标题】:How do I integrate React with a non-trivial AngularJS app and existing grunt configurations?如何将 React 与非平凡的 AngularJS 应用程序和现有的 grunt 配置集成?
【发布时间】:2017-09-29 12:13:03
【问题描述】:

我目前正在创建一个新的 React 组件,该组件需要与现有的 Angular 1.x 应用程序集成,该应用程序本身已经有自己的以 Grunt 为中心的构建过程。在某些时候,应用程序可能会完全迁移到 React,但目前只有这一个组件将在 React 中完成。

Angular 应用程序使用 grunt 围绕它构建了一个广泛的构建过程,因此新组件的任何构建都必须能够通过 grunt。

到目前为止,另一位开发人员已经开始使用 React starter kit 开发 React 组件,其中包括 React、Webpack、Babel、一个可以启动的开发服务器,以及其他各种花里胡哨的东西。

这是我最初的研究成果以及当前的障碍:

  • 看起来 ngReact 将成为将 React 组件集成到应用程序中的好工具。
  • 当前的 React 设置可以启动一个带有 React 应用程序的嵌入式构建的开发服务器(没有真正可用的构建文件),或者创建一个缩小并准备好发布的“生产”构建。这不太好用,因为我需要它来创建当前应用和 ngReact 可以使用的东西。
  • React 应用程序正在使用 Webpack 进行捆绑。有一个 grunt 工具可以运行 webpack 配置。

我怎样才能将所有这些移动部件组合在一起,将 React 组件捆绑到现有的 Angular 应用程序中,同时尽可能多地保留现有配置?

【问题讨论】:

    标签: angularjs reactjs webpack ngreact


    【解决方案1】:

    以下是解决此问题所需的步骤(更改组件/文件名以保护无辜者):

    1. 让 Webpack 输出一个构建,我以后可以通过 ngReact 使用它。在 webpack.config.js 中,我必须将 output:{ path: 'build' } 更改为 build_react 以便以后不会被 Angular 构建过程覆盖。另外,在module.loaders 中,我添加了如下所示的预设行,以使其输出非 ES6 有效的 JavaScript:

      //Process JS with Babel.
      {
        test: /\.(js|jsx)$/,
        include: paths.appSrc,
        loader: 'babel-loader',
        query: {
          presets: ['env', 'react'],
        }
      }
      
    2. 使用 npm 安装 grunt-webpack,并使用指向 webpack 配置文件的链接进行配置。该文件与所有其他类似配置一起被拉入 grunt initConfig。

      //webpackConfig.js
      module.exports.name = 'webpack';
      const webpackConfig = require('../webpack.config.dev.js');
      
      /**
       * Pull in our react webpack build
       */
      module.exports.getConfiguration = function(grunt) {
          return {
              options: {
                  stats: !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
              },
              prod: webpackConfig,
              dev: webpackConfig
          };
      };
      
    3. 在我们的 index.html 文件中包含 react.jsreact-dom.jsng-react.min.js 和 #1 中内置的包。 (这些稍后将被连接到一个文件中以用于生产构建。)至关重要,必须在所有 Angular 文件(包括所有应用程序 .js 文件)之后包含 包,以便 React 组件可以访问angular 对象以进行下一步。

    4. 将此行添加到 React 组件,以便 ngReact 可以工作:angular.module('angularModule').value('MyComponent', MyComponent);
    5. 将以下内容添加到将包含 React 组件的 Angular 模板中:<react-component name="MyComponent"></react-component>

    经过所有这些步骤,它终于奏效了!如果将来有人遇到此问题,希望这将有助于有人将这些步骤放在一起。

    【讨论】:

    • ,谢谢你的问题,我现在正在寻找这个答案
    【解决方案2】:

    我在将 React 集成到当前 AngularJs 构建过程中时遇到了同样的问题,但是作为一个单独的应用程序。它可能会对你有所帮助。

    这是 React 的完整 grunt 配置:

    它会创建一个单独的任务以使用唯一名称做出反应,因此您可以按照自己的意愿操作它们。

    项目的 Gruntfile.js:

    module.exports = function (grunt) {
    
    let concat = {};
    let clean = {};
    let uglify = {};
    let copy = {};
    let htmlmin = {};
    let cssmin = {};
    let browserify = {};
    let watch = {};
    let template = {};
    let run = {};
    
    /* React configuration. */
    
    const reactSourcePath = './source';
    const reactCompiledPath = './client';
    const reactHtmlPathDest = './client/index.html'
    const reactTargetName = "react";
    const reactFileName = "react_main";
    
    /* ### TASK CONFIGURATIONS ### */ 
    
    /* Clean compiled files. */
    clean[reactTargetName] = [
        `${reactCompiledPath}`
    ];
    
    /* Concatenate all CSS files to one. */
    const cssConcatSourceTemplate = `${reactSourcePath}/**/**.css`;
    const cssDestinationFile = `${reactCompiledPath}/css/${reactFileName}.css`;
    
    concat[reactTargetName] = {
        src: [cssConcatSourceTemplate],
        dest: cssDestinationFile
    };
    
    /* Convert JSX to JS, prepare JS files for a browser and copy to the destination. */
    const jsSourceFile = `${reactSourcePath}/index.js`;
    const jsDestinationFile = `${reactCompiledPath}/js/${reactFileName}.js`;
    
    browserify[reactTargetName] = { 
        options: {
            transform: [['babelify', {presets: ['es2015', 'react']}]]
        },
        files: {
            [jsDestinationFile]: jsSourceFile
        }
    };
    
    /* Replace js/css placeholders and copy html file to destination. */
    const applicationData = {
        css: [
            './css/react_main.css'
        ],
        js: [
            './js/react_main.js'
        ]
    };
    
    var jsFiles = "";
    var cssFiles = "";
    
    applicationData.css.forEach(function(item) {
        cssFiles = cssFiles + `\n<link rel="stylesheet" type="text/css" href=${item}>`;
    });
    
    applicationData.js.forEach(function(item) {
        jsFiles = jsFiles + `\n<script type="text/javascript" src=${item}></script>`;
    });
    
    template[reactTargetName] = {
        options: {
            data: {
                appName: '<%= pkg.name %>' + '-react',
                productVersion: '<%= pkg.version %>',
                reactEmbeddedCssFiles: cssFiles,
                reactEmbeddedJsFiles: jsFiles
            }
        },
        files: {
            [`${reactHtmlPathDest}`]: `${reactSourcePath}/index.template.html`,
        }
    };
    
    /* Uglify react JS file. */
    uglify[reactTargetName] = { 
        files: {
        [jsDestinationFile]: jsDestinationFile
    }
    };
    
    /* Copy bootstrap CSS/JS files. */
    copy[reactTargetName] = {
        files: {
            [`${reactCompiledPath}/css/bootstrap.min.css`]: 'node_modules/bootstrap/dist/css/bootstrap.min.css',
            [`${reactCompiledPath}/js/bootstrap.min.js`]: 'node_modules/bootstrap/dist/js/bootstrap.min.js',
            [`${reactCompiledPath}/js/jquery.min.js`]: 'node_modules/jquery/dist/jquery.min.js',
        }
    }
    
    /* Minify HTML files. */
    htmlmin[reactTargetName] = {
        options: {
            removeComments: true,
            collapseWhitespace: true
        },
        files: {
            [`${reactHtmlPathDest}`]: `${reactHtmlPathDest}`
        }
    };
    
    /* Minify react CSS file. */
    cssmin[reactTargetName] = {
        files: {
            [cssDestinationFile]: cssDestinationFile 
        }
    };
    
    /* Watch for any changes in react app. 
    There are three separate watches for css, js, and html files. */
    watch[reactTargetName + '_css'] = {
        files: [`${reactSourcePath}/**/*.css`],
        tasks: [`concat:${reactTargetName}`],
        options: {
            livereload: true
        }
    };
    
    watch[reactTargetName + '_js'] = {
        files: [`${reactSourcePath}/**/*.js`],
        tasks: [`browserify:${reactTargetName}`],
        options: {
            livereload: true
        }
    };
    
    watch[reactTargetName + '_hmtl'] = {
        files: [`${reactSourcePath}/**/*.html`],
        tasks: [`template:${reactTargetName}`],
        options: {
            livereload: true
        }
    };
    
    /* Jest tests */
    jestTestsTaskName = reactTargetName + '_jest_tests';
    run[jestTestsTaskName] = {
        exec: 'npm test'
      };
    
    /* Generate task names for react. */
    
    var reactTasks = {
        debug: [
            "clean", 
            "browserify", 
            "concat", 
            "copy", 
            "template"
        ].map(x => x + `:${reactTargetName}`),
        release: [
            "clean", 
            "browserify", 
            "concat", 
            "copy", 
            "template", 
            "htmlmin", 
            "uglify", 
            "cssmin"
        ].map(x => x + `:${reactTargetName}`)
    };
    
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        watch:watch,
        copy:copy,
        concat:concat,
        clean:clean,
        uglify:uglify,
        template:template,
        browserify: browserify,
        htmlmin: htmlmin,
        cssmin: cssmin,
        run:run
    });
    
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-template');
    grunt.loadNpmTasks("grunt-browserify");
    grunt.loadNpmTasks("grunt-contrib-htmlmin");
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-run');
    
    grunt.registerTask('react_build_debug', reactTasks.debug);
    grunt.registerTask('react_build_release', reactTasks.release);
    

    }

    【讨论】:

      猜你喜欢
      • 2014-02-05
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多