我目前正在创建一个新的React组件,需要与现有的Angular 1.x应用程序集成,该应用程序本身已经拥有以Grunt为中心的构建过程。在某些时候,应用程序可能会完全迁移到React,但目前只有这一个组件将在React中完成。
Angular应用程序使用grunt围绕它构建了一个广泛的构建过程,因此新组件的任何构建都必须能够通过grunt。
到目前为止,另一位开发人员已经开始使用React starter kit开发React组件,其中包括React,Webpack,Babel,它可以启动的开发服务器,以及其他各种各样的铃声和口哨。
这是我最初的研究成果,以及目前的障碍:
如何将所有这些移动组件放在一起,将React组件捆绑到现有的Angular应用程序中,同时保留尽可能多的现有配置?
答案 0 :(得分:0)
以下是解决此问题所需的步骤(更改了组件/文件名以保护无辜者):
获取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'],
}
}
使用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
};
};
在index.html文件中包含react.js
,react-dom.js
,ng-react.min.js
以及#1中内置的捆绑包。 (这些将在以后连接到生成版本的一个文件中。)至关重要,在所有Angular文件(包括所有应用程序.js
之后)必须包含文件,以便React组件可以访问angular
对象以进行下一步。
angular.module('angularModule').value('MyComponent', MyComponent);
<react-component name="MyComponent"></react-component>
完成所有这些步骤后,它终于奏效了!希望如果有人在将来遇到这个问题,这将有助于某些人将这些步骤放在一起。
答案 1 :(得分:0)
在将React集成到当前的AngularJs构建过程中,我遇到了同样的问题,但是作为一个单独的应用程序。可能会对您有帮助。
这是React的完整配置:
它创建了一个单独的任务以使用唯一的名称进行响应,因此您可以根据需要对其进行操作。
该项目的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);
}