我希望构建一个React应用程序,并将静态的CSS和JS文件有效地嵌入到当我调用yarn build
时生成的index.html中。
显然,我可以通过替换<script src"...
和<link href="/static/css/...
标签为内联版本来完成,但我希望有一种更优雅的解决方案。
我希望构建一个React应用程序,并将静态的CSS和JS文件有效地嵌入到当我调用yarn build
时生成的index.html中。
显然,我可以通过替换<script src"...
和<link href="/static/css/...
标签为内联版本来完成,但我希望有一种更优雅的解决方案。
我搞定了。供日后参考(使用react 16.7.0和yarn 1.10.1)...
创建一个React应用:
npx create-react-app my-app
cd my-app
yarn build
一切都好吗?太好了,运行eject
以便您可以访问webpack配置:
yarn eject
rm -rf build node_modules
yarn install
yarn build
添加该项目并更新webpack:
yarn add html-webpack-plugin@4.0.0-beta.4
yarn add html-webpack-inline-source-plugin@1.0.0-beta.2
编辑config/webpack.config.js
:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); <--- add this
...
plugins: [
new HtmlWebpackPlugin(
Object.assign(
...
isEnvProduction
? {
inlineSource: '.(js|css)$', <-- add this
minify: {
...
),
...
isEnvProduction &&
shouldInlineRuntimeChunk &&
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin), <--- add this
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
...
运行命令rm -rf build && yarn build && serve -s build
- 你加载的index.html
现在应包含所有js和css内容。请注意,静态文件仍然创建在build目录中,但页面不会使用它们。
之前的答案都不适用了,因为 html-webpack-inline-source-plugin
已经不再被支持,作者已经用官方插件 html-inline-script-webpack-plugin
和 html-inline-css-webpack-plugin
进行了替换。以下方法可以在最新的React 17中(截至2021年10月)使用。具体步骤如下:
创建一个React应用
create-react-app my-app
cd my-app
yarn
yarn start
确保它能工作,并且你对输出结果感到满意。然后,弹出你的配置文件(我认为这可以在不弹出配置文件的情况下完成,但我懒得查找如何配置CRA)
yarn eject
rm -rf build node_modules
yarn
yarn build
然后,添加Webpack插件(假设你想在这里嵌入CSS和脚本,请删除其中一个如果你只想要另外一个)
yarn add html-inline-css-webpack-plugin -D
yarn add html-inline-script-webpack-plugin -D
最后,在 Webpack 配置文件 config/webpack.config.js
中添加这些内容。首先在文件顶部声明它们:
const HTMLInlineCSSWebpackPlugin = require('html-inline-css-webpack-plugin').default;
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
然后将它们添加到plugins: [...]
集合中。搜索new InlineChunkHtmlPlugin
,并将它们添加在其后面:
isEnvProduction &&
shouldInlineRuntimeChunk &&
new HTMLInlineCSSWebpackPlugin(),
isEnvProduction &&
shouldInlineRuntimeChunk &&
new HtmlInlineScriptPlugin(),
注意: 包括 isEnvProduction
/ shouldInlineRuntimeChunk
检查非常重要!如果您跳过这些检查,当您运行 yarn start
时,热更新将无法正常工作。您只想在生产模式下嵌入脚本,而不是在开发期间嵌入。
现在,如果您运行 yarn build
,您会发现所有的 CSS 和 JS 都被嵌入到 build/index.html
中。如果您运行 yarn start
,它将启动一个热重载开发环境,您可以在其中进行开发。
createRoot(...): Target container is not a DOM element.
在 HtmlWebpackPlugin
中添加 inject: 'body'
解决了这个问题。然而,我仍然遇到了静态资源链接损坏的问题。通过将 PUBLIC_URL 环境变量设置为“.”,例如:"build": "PUBLIC_URL=. node scripts/build.js",
我解决了这个问题。 - Andrew Aarestad下面原本链接的插件已经不再维护。虽然有多个分支进行了更新,但似乎没有一个是活跃维护的。目前支持 Webpack 5 的最新选项如下:
https://www.npmjs.com/package/html-webpack-inline-source-plugin-next
根据它的README,它的工作方式与原始插件相同。请指定:var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin-next');
然后您可以像以前一样传递插件。
为此目的创建了一个Webpack插件:
https://www.npmjs.com/package/html-webpack-inline-source-plugin
如README所指定,这必须与html-webpack-plugin一起使用,并且您必须指定传递的inlineSource
:
plugins: [
new HtmlWebpackPlugin({
inlineSource: '.(js|css)$' // embed all javascript and css inline
}),
new HtmlWebpackInlineSourcePlugin()
]
new HtmlWebpackInlineSourcePlugin()
替换为 new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin)
,以使其正常工作。 - keikai虽然我无法使用之前提供的所有答案将其运行起来,但我想通过提供一些链接来帮助任何试图找到解决方案的人:
https://github.com/facebook/create-react-app/issues/3365#issuecomment-376546407
使用create-react-app生成单个物理JavaScript文件
在不使用HtmlWebpackInlineSourcePlugin的情况下使用Webpack内联CSS?
https://www.labnol.org/code/bundle-react-app-single-file-200514
对于我非常简单的用例,缩小等并不是那么重要,因此我将使用修改后的React网站示例(示例下载在这里)。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
</head>
<body>
<h2>Add React in One Minute</h2>
<p>This page demonstrates using React with no build tooling.</p>
<p>React is loaded as a script tag.</p>
<!-- We will put our React component inside this div. -->
<div id="root"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<script type="text/babel">
'use strict';
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
render() {
if (this.state.liked) {
return 'You liked this.';
}
return <button onClick={() => this.setState({ liked: true })} > Like </button >;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<LikeButton />)
</script>
</body>
</html>
@Jansky的回答对我很有帮助,太好了!不过,我想跟进一下,因为有一种方法可以在不弹出应用程序或搞乱react-scripts/config/webpack.config.js
文件的情况下进行这些修改。这包括重写HtmlWebpackPlugin以内联脚本到body中。
其他人可能无法使此方法正常工作,因为创建了webpack.config.js并未在使用create-react-app时使用自己的项目。
这适用于我的webpack5,react17
npm install react-app-rewired --save-dev
react-app-rewired
而不是 react-scripts
/* package.json */
"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
- "build": "react-scripts build",
+ "build": "react-app-rewired build",
- "test": "react-scripts test",
+ "test": "react-app-rewired test",
"eject": "react-scripts eject"
}
config-overrides.js
文件,内容如下:const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlInlineCssWebpackPlugin = require('html-inline-css-webpack-plugin').default;
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
module.exports = {
webpack: function (config, env) {
//inline css and scripts right after chunk plugin.
//chunk plugin will not be present for development build and thats ok.
const inlineChunkHtmlPlugin = config.plugins.find(element => element.constructor.name === "InlineChunkHtmlPlugin");
if (inlineChunkHtmlPlugin) {
config.plugins.splice(config.plugins.indexOf(inlineChunkHtmlPlugin), 0,
new HtmlInlineCssWebpackPlugin(),
new HtmlInlineScriptPlugin()
);
}
//Override HtmlWebpack plugin with preserving all options and modifying what we want
const htmlWebpackPlugin = config.plugins.find(element => element.constructor.name === "HtmlWebpackPlugin");
config.plugins.splice(config.plugins.indexOf(htmlWebpackPlugin), 1,
new HtmlWebpackPlugin(
{
...htmlWebpackPlugin.userOptions,
inject: 'body'
}
)
);
return config;
}
}