本文也同步发表在个人公众号“个人天空”html
从零开始,用最少的配置、最少的代码、最少的依赖来搭建一个最简单的webpack+react环境。前端
最近在玩webpack+react+移动端,那么第一步天然是搭建相关的环境,原本网上的教程很不错,只是前端相关的东西发展太过迅猛,只相隔了半年有些东西的版本就不对了,有些配置、命令等照着以前的教程作就可能会掉到坑里去,别问我怎么知道的,我刚刚从坑里爬出来,所以赶忙写篇文章来记录一下,也算是让本身再巩固一下。node
本篇彻底是从零开始,用最少的配置、最少的代码、最少的依赖来搭建一个最简单的webpack+react环境。会把一个小白的经历原本来本的写出来,遇到的坑都用红色的坑字标注出来,因为我也是第一次学习相关的知识点若是有不正确的地方也多多欢迎你们来指出。react
本篇文章写做的日期是2018-7-21,所以全部依赖的版本到当前日期为止,之后若是有升级变化的话,那也是没法当前预料获得的。个人操做系统是win7,所以不涉及到linux的相关知识点。编辑器是Sublime Text3.0,顺便安利一下Sublime Text,好用速度又快,真心不错!
linux
我是参考这篇教程:https://segmentfault.com/a/1190000006178770webpack
如今让咱们开始吧,第一步咱们先配置一个webpack的web服务器。es6
webpack依赖于node.js,那么第一步是安装node.js,这个没什么好说的,windows环境的安装就更友好了,官网下载安装包,一路默认安装便可,如今的node.js安装完毕后,npm也就自带安装好了,后面咱们就要一路与npm打交道了。web
首先咱们要用npm初始化项目,电脑上新建一个目录保存咱们的练习文件,随后进入cmd命令行,转到该目录下。若是命令行不会操做的话,请先掌握cd这个命令。接下来在该目录下输入npm init命令:npm
npm init
根据提示一路回车就能够了,不过这个地方可能会有一个坑存在,如图:json
这里报错:Sorry,name can only contain URL-friendly characters。
该错误产生的缘由是npm初始化时,会向咱们询问项目名,若是咱们不指定的话(一般都是如此),那么就会用当前文件夹来命名,而咱们的文件夹的名称为“练习-react环境”,其包含了一个中划线(-),所以致使命名错误了。那么咱们只要输入一个项目名称(譬如test)就能够了, 或者干脆把文件夹重命名为符合规范的名称就能够了。
本例中咱们手动输入了test,将项目名称指定为test:
接下来就一路回车,最后询问“Is this OK?<y>”时输入y后回车,完成npm初始化。
npm初始化后,在文件夹下将会出现一个node_modules文件夹(目前为空),以及pack.json文件。其实咱们刚才npm init命令就是为了配置这个package.json,所以也能够彻底本身来手动建立。
接下来安装webpack和webpack-dev-server,执行命令:
npm install webpack webpack-dev-server --save-dev
安装webpack很顺利,没有遇到任何问题。
安装完毕后,node_modules文件夹中就再也不为空了,里面存放的都是webpack的相关依赖。package.json中也多了"dependencies"和"devDependencies"两项,其记录的是当前依赖及版本信息,其中"dependencies"为空。
"devDependencies": { "webpack": "^4.16.1", "webpack-dev-server": "^3.1.4" }, "dependencies": { }
随后在当前文件夹下新建一个public文件夹(文件夹名任意),在里面写一个index.html页面,内容随意。接下来咱们就要配置webpack了,在文件夹下新建一个webpack.config.js文件,此时目录结构为:
编辑webpack.config.js,因为咱们的目的是建立一个web服务器,所以只须要配置如下内容:
module.exports={ devServer:{ contentBase:"./public" } }
devServer是webpack中web服务器的相关配置项,contentBase指定的是页面加载目录,而其加载页面默认为index.html,因为咱们的index.html是在public目录下,所以就将contentBase设置为"./public“。
接下来在package.json中配置web服务启动命令,该命令配置在scripts中的,其命令名称为“server”,命令详情为“webpack-dev-sever --open”:
"server":"webpack-dev-server --open"
将其插入scripts中:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "server": "webpack-dev-server --open" },
在命令行中输入"npm run server”回车以便启动web服务,此时会遇到一个坑,webpack并无启动web服务,而是报错:
其大意是缺乏webpack-cli,那么咱们天然就安装这个webpack-cli,执行命令:
npm install webpack-cli --save-dev
webpack-cli安装过程很顺利,随后再执行“npm run server”就能够正常启动web服务了,而且启动默认浏览器,显示public下的Index.html页面,web服务的默认端口是8080。
至此,咱们第一部分的目的:启动一个web服务便完成了,总结一下,要从零开始启动webpack的web服务须要作:
安装node.js、npm
安装webpack、webpack-cli、webpack-server-dev
npm初始化
编写一个显示页面并命名为index.html
建立webpack.config.js,并配置devServer信息。
配置package.json,设置web启动命令。
到目前为止,咱们丝毫未说起另外一位主角:react,接下来咱们就继续搭建环境,让其支持react。首先天然是要安装react,咱们须要安装react和react-dom,执行命令:
npm install react react-dom --save
因为react是在正式环境中也须要的,所以npm安装时没有带-dev参数。
接下来修改以前的index.html,无论之前是怎么编写的,请在HTML中增长一个 <div>,将其的ID设置为"boot“,同时编写外部js引入,引入的js名为bundle.js。
<body> <div id='root'></div> <script src='bundle.js'></script> </body>
接下来在public目录下建立index.jsx文件,注意后缀名是jsx,其内容为:
import React from 'react' import { render } from 'react-dom' class Hello extends React.Component { render() { return ( <p>hello react!</p> ) } } render( <Hello/>, document.getElementById('root') )
react的语法细节咱们暂时不关心,只要知道最后页面上会输出hello react!就能够了。
jsx是react的专用语法,HTML是没法引用的,所以咱们须要将其转换为HTML可以识别的JS,而这个正是webpack大显身手的时候,咱们开始来配置webpack,配置以前,再确认一下的当前的目录结构:
首先咱们是经过babel来转换jsx的,所以须要安装babel相关的环境,咱们须要安装:
babel-core
babel-loader
babel-preset-es2015
babel-preset-react
执行命令:
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
因为咱们要转换的源文件是index.jsx,转换后的目标文件是bundle.js,所以须要在webpack中配置入口和出口,在文本webpack.config.js中增长如下内容:
entry:__dirname+"/public/index.jsx",
output:{
path:__dirname+"/public",
filename:'bundle.js'
}
entry是转换的入口,而output是转换的出口。
同时还要在webpack.config.js中配置loader,让其经过外部工具来处理文件,而咱们当前要处理的是经过babel来处理jsx文件。所以到了这一步咱们大体会有些明白了,并非webpack自己帮咱们处理这些,而是像个中介同样,把要处理的部分与相关的工具联系在一块儿。
咱们在webpack.config.js中加入:
module: { loaders: [ { test: /\.(jsx)$/, exclude: /node_modules/, loader: 'babel' } ] }
其代表jsx文件须要用babel来处理,可是对于node_modules文件夹中的文件忽略掉(exclude设置)。此时webpack.config.js的内容就是:
module.exports={ entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public" }, module: { loaders: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel' } ] } };
照理来讲,到了这一步全部该作的事情都已经作完了,经过babel将index.jsx解析成bundle.js,Web服务将启动index.html,而index.html会引入bundle.js,最后在页面上显示hello react!
可是,事情每每不是那么顺利的,接下里要继续踩坑!首先咱们先执行npm run server看看是什么状况:
立刻就遇到坑,刺眼的红色错误提示,意思竟然是loaders属性无效?!问题出如今webpack版本上,咱们安装的版本是4.16.1,此时webpack.config.js中loaders的写法已通过时,应该用rules,同时babel也应该用babel-loader来替代,实际的写法为:
module: { rules: [ { test: /\.(jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] }
此时webpack.config.js的内容为:
module.exports={ entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public" }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] } };
接下来继续试试npm run server,依然报错:
此处仍然有一坑!因为咱们的jsx是用es6语法编写的,所以须要经过label来解析,那么实际上此处还缺乏一个文件,就是“.babelrc”,注意这是一个名称很奇葩的文件,只有扩展名而没有文件名,该文件在windows环境下是没法经过资源管理器建立的,须要到命令行下执行type null>.babelrc命令:
type null>.babelrc
虽然提示“系统找不到指定的文件”,可是实际上已经建立了.babelrc文件,随后用文本编辑器将该文件打开,输入内容:
{ "presets": ["react", "es2015"], "env": { "dev": { "plugins": [["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }]] } } }
至此,再执行npm run server,终于能够看到页面正常显示了!
如果此时页面还不能正常显示的话,也许就要清理下缓存,从新生成bundle.js文件。或者在package.json中的scripts中增长“start“命令,其值为“webpack”,即:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" },
这样在命令行中执行“npm start”就能够从新编译jsx为bundle.js了。
npm start
再总结一下咱们遇到的坑:
npm初始化时的项目名称要合规,特别是不能出现中划线下划线。
安装webpack-cli。
loaders已过期,须要替换为rules。
须要建立.babelrc文件。
至此咱们便搭建了一个最简单的webpack+react环境,当咱们修改index.jsx中的内容时,页面刷新后也会发生改变,接下来就能够好好学习react了!
固然,咱们能够更改webpack.config.js中的devServer,添加inline:true,这样即可以实现jsx更改后,页面会自动刷新,不用咱们每次修改后都去手动刷新去看效果了。另外再增长mode:"development",这样刷新的速度会大大加快!
最终的文件目录结构为:
各文件的最终内容:
index.html
<!DOCTYPE html> <html> <head> </head> <body> <div id='root'></div> <script src='bundle.js'></script> </body> </html>
index.jsx
import React from 'react' import { render } from 'react-dom' class Home extends React.Component{ render(){ return( <p>Hello react!</p> ) } } render( <Hello />,document.getElementById('root') )
.babelrc
{ "presets": ["react", "es2015"], "env": { "dev": { "plugins": [["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }]] } } }
package.json
{ "name": "test", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "webpack": "^4.16.1", "webpack-dev-server": "^3.1.4" }, "dependencies": { "react": "^16.4.1", "react-dom": "^16.4.1", } }
webpack.config.js
module.exports={
mode:"development", entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public",
inline:true
}, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] } };