最小白的webpack+react环境搭建
本文也同步发表在我的公众号“我的天空”
从零开始,用最少的配置、最少的代码、最少的依赖来搭建一个最简单的webpack+react环境。
最近在玩webpack+react+移动端,那么第一步自然是搭建相关的环境,本来网上的教程很不错,只是前端相关的东西发展太过迅猛,只相隔了半年有些东西的版本就不对了,有些配置、命令等照着之前的教程做就可能会掉到坑里去,别问我怎么知道的,我刚刚从坑里爬出来,因此赶紧写篇文章来记录一下,也算是让自己再巩固一下。
本篇完全是从零开始,用最少的配置、最少的代码、最少的依赖来搭建一个最简单的webpack+react环境。会把一个小白的经历原原本本的写出来,遇到的坑都用红色的坑字标注出来,由于我也是第一次学习相关的知识点如果有不正确的地方也多多欢迎大家来指出。
本篇文章写作的日期是2018-7-21,因此所有依赖的版本到当前日期为止,以后如果有升级变化的话,那也是无法当前预料得到的。我的操作系统是win7,因此不涉及到linux的相关知识点。编辑器是sublime text3.0,顺便安利一下sublime text,好用速度又快,真心不错!
我是参考这篇教程:https://segmentfault.com/a/1190000006178770
现在让我们开始吧,第一步我们先配置一个webpack的web服务器。
webpack依赖于node.js,那么第一步是安装node.js,这个没什么好说的,windows环境的安装就更友好了,官网下载安装包,一路默认安装即可,现在的node.js安装完毕后,npm也就自带安装好了,后面我们就要一路与npm打交道了。
首先我们要用npm初始化项目,电脑上新建一个目录保存我们的练习文件,随后进入cmd命令行,转到该目录下。如果命令行不会操作的话,请先掌握cd这个命令。接下来在该目录下输入npm init命令:
npm init
根据提示一路回车就可以了,不过这个地方可能会有一个坑存在,如图:
这里报错: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' } ] } };
上一篇: 浅谈thinkphp的实例化模型
下一篇: PHP实现普通hash分布式算法简单示例