今天按照网上的教程学习了webpack+react,虽然在浏览器中访问http://localhost:8080/可以看到效果,但还是有好多疑问。
npm start
webpack-dev-server --hot --inline
后却找不到打包后的bundle.js文件,这个bundle.js文件在哪呢?npm run build
打包后的bundle.js文件可以看到,但是在浏览器中访问index.html文件的绝对路径页面什么都没有,console中提示Download the React DevTools and use an HTTP server (instead of a file: URL) for a better development experience:,因为我的Apache服务器根目录是www,在浏览器中访问http://localhost/public/index.html
也没有任何反应,console中提示Download the React DevTools for a better development experience:。难道我只能用http://localhost:8080/
访问吗?怎么才能访问http://localhost/public/index.html
有效果,也就是说如何把打包后的文件放在Apache服务器中部署。
项目目录树:
package.json文件 scripts部分:
"scripts": {
"start": "webpack-dev-server --hot --inline",
"build": "webpack --progress --profile --colors --config webpack.production.config.js"
},
webpack.config.js:
let path = require('path');
//定义了一些文件夹的路径
let ROOT_PATH = path.resolve(__dirname);
let APP_PATH = path.resolve(ROOT_PATH, 'app');
let BUILD_PATH = path.resolve(ROOT_PATH, 'public');
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + '/app/main.js',
output: {
path: BUILD_PATH,
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.less$/,
loaders: ['style', 'css', 'less','postcss'],
include: APP_PATH
},
{
test: /\.jsx?$/,
loader: 'babel',
include: APP_PATH,
resolve: {
extensions: ['', '.js', '.jsx']
}
}
]
},
postcss: [
require('autoprefixer')//调用autoprefixer插件
],
devServer: {
contentBase: './public',
colors: true,
historyApiFallback: true,
inline: true
}
}
webpack.production.config.js:
let path = require('path');
let webpack = require('webpack');
//定义了一些文件夹的路径
let ROOT_PATH = path.resolve(__dirname);
let APP_PATH = path.resolve(ROOT_PATH, 'app');
let BUILD_PATH = path.resolve(ROOT_PATH, 'public');
let ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + '/app/main.js',
output: {
path: BUILD_PATH,
filename: 'bundle.js'
},
module: {
loaders: [
{
test : /\.(less|css)$/,
loader: ExtractTextPlugin.extract('style', 'css!less')
},
{
test: /\.jsx?$/,
loader: 'babel',
include: APP_PATH,
resolve: {
extensions: ['', '.js', '.jsx']
}
}
]
},
postcss: [
require('autoprefixer')//调用autoprefixer插件
],
plugins: [
//new webpack.optimize.UglifyJsPlugin(),
//new webpack.optimize.CommonsChunkPlugin('common.js'),
new ExtractTextPlugin('css/[name].css')
]
}
.babelrc:
{
"presets": ["react", "es2015"],
"env": {
// only enable it when process.env.NODE_ENV is 'development' or undefined
"development": {
"plugins": [["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
// if you use React Native, pass "react-native" instead:
"imports": ["react"],
// this is important for Webpack HMR:
"locals": ["module"]
}]
// note: you can put more transforms into array
// this is just one of them!
}]]
}
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
main.js入口文件
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
constructor(props) {
super(props);
}
render() {
let backgroundSrc = './imgs/gondel.jpg';
return (
<div>
{backgroundSrc}
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById('root'));
访问http://localhost/public/index.html
时浏览器错误提示:
我觉得你还没有弄清楚文件的路由是怎么回事
一个html文件中会纪录它要载入哪些脚本,然后就会向对应的URI(统一资源标识符)去请求这个资源。
比如你上面的html文件中纪录了请求src为bundle.js的文件,因为你正在访问
http://localhost:8080/
的地址,那么浏览器会将其解析为http://localhost:8080/bundle.js
,而webpack-dev-server在运行的时候就会根据你的配置(具体就是output中的publicPath来决定)将其提供给访问者,而你没有配置的情况下(path是webpack,不是webpack-dev-server用的,用于production build的时候确定生成文件的位置),他就默认是webpack-dev-server当前监听的端口的根目录,于是你就能正常获得这个bundle.js。而在npm run watch的过程中,它是不会生成实际的脚本文件的,都是根据需要提供给访问者。假如你把webpack-dev-server的output的publicPath定义为"/js/",那么你就应该去
http://localhost:8080/js/bundle.js
来获得这个资源。那么问题来了,你有没有遇到过,比如你网页在前端做路由的时候来到了比如
http://localhost:8080/here/
的地址,然后修改了代码导致自动刷新然后提示你找不到bundle.js的时候,只有前往http://localhost:8080/
才能刷新成功?那是因为根据解析规则,此时类似src="bundle.js"的uri会被解析为http://localhost:8080/here/bundle.js
,发现问题了没,你没有指定绝对路径就会出这种错。所以我建议你将这个地址改为src="http://localhost:8080/bundle.js"
或者简单点(也便于以后部署)src="/bundle.js"。
这个知识点在开发网页时候很常用的,比如a标签的href,你可以试一下都是同样的逻辑。当你react app开发完成之后,实际部署的过程中,需要部署。用户实际访问的顺序是这样的,用户先访问你的服务器,然后你返回一个html文件给他,上面纪录了需要加载的脚本文件的uri,你就要保证从一个uri能够访问到这个bundle.js,这种访问是最简单的对于文件的访问,不管是通过浏览器的开发者工具还是直接访问,你都应该看到实际获得了这个文件。
那么你可以打开,比如chrome的开发工具,来到network这一块,查看这个html加载的时候尝试去哪里获取js文件,根据你的html的写法,
http://localhost/public/index.html
是你访问使用的地址,src="bundle.js",那么浏览器访问bundle.js的地址就是http://localhost/public/bundle.js
,至于你到底有没有把bundle.js放在这个路由下,我就不知道啦。你也可以通过浏览器地址栏直接输入http://localhost/public/bundle.js
来看看是否实际访问到了这个文件。这是很正常的文件可访问测试,和其他时候你需要使用一些静态资源(图片什么的)都是一样的测试方法。
另外需要关注的就是webpack实际打包文件(不是webpack-dev-server)的时候,output中的publicPath仍然有用。比如你通过react-router做module的按需加载,打个比方吧,你的app分为三个大块,一个是index块,一个是用户中心块,一个是网站功能块,假设他们都很大,各有300K。因为用户首先访问的肯定是index块,你肯定就希望不要打出一个900K的包(实际更大,因为你肯定会引入很多其他的包),而是按需加载。那么给用户中心块和网站功能块做了按需加载之后,他们就会被生成0.js,1.js这样的会被按需加载的模块,在访问到对应路由的时候才会临时从服务器上下载。
此时你在webpack设置中output里的publicPath就会起作用,比如我设置的"/js/",我网站假设是
http://www.test.com/
,那么当app需要0.js这个模块的时候,虽然html里面没有写,但是就会自动去http://www.test.com/js/0.js
这个uri去获取脚本