我如何将 React 与一个重要的 AngularJS 应用程序和现有的 grunt 配置集成?
How do I integrate React with a non-trivial AngularJS app and existing grunt configurations?
我目前正在创建一个新的 React 组件,该组件需要与现有的 Angular 1.x 应用程序集成,该应用程序本身已经有自己的以 G[=35= 为中心的构建过程]吨。在某些时候,应用程序可能会完全迁移到 React,但目前只有这个组件将在 React 中完成。
Angular 应用程序使用 g运行t 围绕它构建了一个广泛的构建过程,因此新组件的任何构建都必须能够通过 g运行 t也是。
到目前为止,另一位开发人员已经开始使用 React starter kit 开发 React 组件,其中包括 React、Webpack、Babel、一个可以启动的开发服务器以及各种其他功能。
这是我最初的研究成果以及当前的障碍:
- 看起来 ngReact 将是一个将 React 组件集成到应用程序中的好工具。
- 当前的 React 设置可以使用 React 应用程序的嵌入式构建(没有真正可用的构建文件)启动开发服务器,或者创建一个 "production" 缩小并准备发布的构建。这不太有效,因为我需要它来创建当前应用程序和 ngReact 可以使用的东西。
- 正在使用 Webpack 捆绑 React 应用程序。有一个 g运行t 工具可以 运行 webpack 配置。
我如何将所有这些移动的部分组合在一起,将 React 组件捆绑到现有的 Angular 应用程序中,同时尽可能多地保留现有配置?
以下是解决此问题所需的步骤(component/file 更改名称以保护无辜者):
让 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,并使用 link 将其配置到 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
对象。
- 将此行添加到 React 组件,以便 ngReact 工作:
angular.module('angularModule').value('MyComponent', MyComponent);
- 将以下内容添加到将包含 React 组件的 Angular 模板中:
<react-component name="MyComponent"></react-component>
经过所有这些步骤,终于成功了!如果将来有人遇到此问题,希望这将有助于将这些步骤放在一起。
我在将 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);
}
我目前正在创建一个新的 React 组件,该组件需要与现有的 Angular 1.x 应用程序集成,该应用程序本身已经有自己的以 G[=35= 为中心的构建过程]吨。在某些时候,应用程序可能会完全迁移到 React,但目前只有这个组件将在 React 中完成。
Angular 应用程序使用 g运行t 围绕它构建了一个广泛的构建过程,因此新组件的任何构建都必须能够通过 g运行 t也是。
到目前为止,另一位开发人员已经开始使用 React starter kit 开发 React 组件,其中包括 React、Webpack、Babel、一个可以启动的开发服务器以及各种其他功能。
这是我最初的研究成果以及当前的障碍:
- 看起来 ngReact 将是一个将 React 组件集成到应用程序中的好工具。
- 当前的 React 设置可以使用 React 应用程序的嵌入式构建(没有真正可用的构建文件)启动开发服务器,或者创建一个 "production" 缩小并准备发布的构建。这不太有效,因为我需要它来创建当前应用程序和 ngReact 可以使用的东西。
- 正在使用 Webpack 捆绑 React 应用程序。有一个 g运行t 工具可以 运行 webpack 配置。
我如何将所有这些移动的部分组合在一起,将 React 组件捆绑到现有的 Angular 应用程序中,同时尽可能多地保留现有配置?
以下是解决此问题所需的步骤(component/file 更改名称以保护无辜者):
让 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,并使用 link 将其配置到 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
对象。- 将此行添加到 React 组件,以便 ngReact 工作:
angular.module('angularModule').value('MyComponent', MyComponent);
- 将以下内容添加到将包含 React 组件的 Angular 模板中:
<react-component name="MyComponent"></react-component>
经过所有这些步骤,终于成功了!如果将来有人遇到此问题,希望这将有助于将这些步骤放在一起。
我在将 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);
}