2

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

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

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

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

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

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

4

2 回答 2

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>

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

于 2017-05-02T04:08:10.933 回答
0

我在将 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);

}

于 2018-08-06T22:27:48.373 回答