接着上一篇
上一篇讲到使用IDE工具如webstorm检测文件的变化,自动编译jsx、es6格式的文件,使其编程浏览器识别的javascript代码。但是最后还是有点问题,就是有些语法还是不支持。
最终只能使用强悍的打包工具webpack来实现了。
安装webpack:
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack
如果项目中已经有了package.json则不需要init。
安装完成之后,在项目根目录创建index.html:
<html>
<head>
<title>webpack 2 demo</title>
<script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
<script src="app/index.js"></script>
</body>
</html>
在根目录创建一个子目录app在子目录再创建index.js
function component () {
var element = document.createElement('div');
/* lodash is required for the next line to work */
element.innerHTML = _.join(['Hello','webpack'], ' ');
return element;
}
document.body.appendChild(component());
进入到项目根目录:
./node_modules/.bin/webpack app/index.js dist/bundle.js
打包后就可以看到在dist生成了bundle.js文件。如果此过程出现一下错误:
则不要使用全局的webpack,使用本项目/node_modules/.bin模块下的webpack。如果接着报错,如:
错误原文如下:
**Invalid configuration object. Webpack has been initialised using a configuration
object that does not match the API schema.
- configuration.context: The provided value “e:\Githome\github\webpack-demos
\demo14” is not an absolute path!**
**Module not found: Error: Cannot resolve module ‘dataa’ in e:\Githome\github\webp
ack-demos\demo14
@ ./main.jsx 3:11-27**
则可能是一些包的依赖没有安装,为了省事,一次性安装下面所有的依赖。
"babel-core": "6.x",
"babel-loader": "6.x",
"babel-preset-es2015": "6.x",
"babel-preset-react": "6.x",
"bundle-loader": "^0.5.4",
"css-loader": "0.x",
"file-loader": "0.x",
"history": "^1.17.0",
"html-webpack-plugin": "2.x",
"jquery": "3.x",
"jsx-loader": "~0.13.2",
"open-browser-webpack-plugin": "0.x",
"react": "15.x",
"react-dom": "15.x",
"react-router": "2.x",
"style-loader": "0.x",
"url-loader": "~0.5.6",
"webpack": "1.x",
"webpack-dev-server": "1.x"
安装方法可以一个一个去npm install webpack –save-dev等,也可以将所有依赖赋值到package.json中,进入package.json所在项目根目录,直接执行npm install,然后等待安装。安装结束后会在本项目生成node_modules目录。
如果打包成功则会出现:
以上是打包简单的js文件,打包react文件,如下:
- 安装模块所有的依赖上面过程已经安装完成。
- 配置路径等参数。项目结构如下
其中index.html内容:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="example"></div>
<script src="../../dist/bundle.js"></script>
</body>
</html>
index.js内容:
//使用状态提升制作温度转换器
//两个input将摄氏度转换为华氏度
import React from 'react';
import ReactDOM from 'react-dom';
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
};
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
//this.setState({temperature: e.target.value});
console.log(e.target);
this.props.onTemprature({scale:this.props.name,temperature: e.target.value});
}
render() {
const temperature = this.props.temperature;
const scale = this.props.name;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
class Calculator extends React.Component {
constructor(props) {
super(props);
this.onTemprature = this.onTemprature.bind(this);
this.state = {temperature: '', scale: 'c'};
}
onTemprature(childValue){
this.setState({scale:childValue.scale,temperature:childValue.temperature});
//if(childValue.scale === 'c'){
// fahrenheit=tryConvert(childValue.temperature, toFahrenheit);
//}else {
// celsius=tryConvert(childValue.temperature, toCelsius);
//}
//如果想在下面的render函数中使用本函数的变量则可以将此变量放到state中
//状态改变了才可以触发render
}
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput name="c" onTemprature={this.onTemprature} temperature={celsius}/>
<TemperatureInput name="f" onTemprature={this.onTemprature} temperature={fahrenheit}/>
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
ReactDOM.render(
<Calculator />,
document.getElementById('example')
);
//https://addons.mozilla.org/zh-CN/firefox/addon/react-devtools/
main.js内容:
document.write('<h1>Hello World</h1>');
webpack.config.js配置:
module.exports = {
entry: ['./project/demo01/index.js','./project/demo01/main.js'],
output: {
filename: 'bundle.js',
path: __dirname+'/dist'
},
module: {
loaders:[
{ test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' },
]
}
};
以上配置就是:将project项目中demo01中的index.js和main.js文件打包到项目路径下的dist目录下的bundle.js中,并且使用的loader是babel和react,且忽略node_modules文件下的jsx文件。至于loaders相关配置可以参考:Loaders
1. ./node_modules/.bin/webpack --config webpack.config.js
2. 访问浏览器http://localhost:63343/react_demos/project/demo01/index.html
3. 如果出现一下错误:Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
,则html文件中的script代码放置位置有问题。在脚本执行时,document 元素还没渲染结束,但是在react中却需要document 元素去render,所以会报错,解决办法,不要将script脚本文件的引入放到head中而是放到body中。[By the time script is executed, document element is not available, because script itself is in the head. While it's a valid solution to keep script in head and render on DOMContentLoaded event, it's even better to put your script at the very bottom of the body and render root component to a div before it:](http://stackoverflow.com/questions/26566317/invariant-violation-registercomponent-target-container-is-not-a-dom-elem)
但是按照本文的步骤是不会报错的。
4. 打包后效果就是:
可见页面上的helloworld说明main.js已经被打包到index.js中了。并且本身的index.js中的代码都可以显示。
以上代码可以在github中或者码云中看到,欢迎fork和star
以上为作者原创,请勿转载,转载请说明出处。