虽然可以利用脚手架快速搭建项目环境,但是我还是想webpack的基本配置也需要熟悉,需要自己从0开始搭建几遍。
1.新建工程文件夹,在文件夹下初始化项目,一路回车
npm init
2.安装webpack,在webpack4中, 需要同时安装webpack和webpack-cli, 因为两者在webpack4中分开管理了
npm i webpack webpack-cli -D
3.新建webpack开发配置文件
touch webpack.config.js
webpack.config.js中配置内容
const path = require('path');
module.exports = { // 入口文件 entry: {
app: './src/index.js'
}, // 输出到dist文件夹, 文件名字为bundle.js output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'./dist')
}
}
新建src目录然后在里面新建index.js文件
mkdir src && cd src && touch index.js
在index.js里面输入
console.log('Hello World!');
配置package.json文件, 在scripts里面加入"build"
"build": "webpack --config webpack.config.js --color --mode production"
回到根目录, 在命令行里输入npm run build, 看到如下信息则编译成功
Hash: 71e9a8e6cb8c777f140b
Version: webpack 4.33.0
Time: 360ms
Built at: 2019-06-11 22:59:42
Asset Size Chunks Chunk Names
bundle.js 957 bytes 0 [emitted] app
Entrypoint app = bundle.js
[0] ./src/index.js 32 bytes {0} [built]
3.安装react和react-dom
npm install react react-dom --save
// npm i react react-dom -S
使用 babel来编译react中使用的JSX语法
npm i babel-core babel-loader babel-preset-env babel-preset-react -D
其中babel-core是核心文件, babel6推荐使用 babel-preset-env 来对ES2015及更高版本进行转换, babel-preset-react能够转换JSX语法
- 在根目录下新建babel配置文件.babelrc
touch .babelrc
配置.babelrc文件:
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": []
}
如有需要,安装ES7转义工具:
npm install @babel/plugin-transform-runtime --save-dev
npm install @babel/runtime --save
配置.babelrc文件:
"plugins": ["@babel/transform-runtime"]
webpack.config.js增加babel-loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
- 修改src文件夹里面index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render( <h1>Hello World</h1>,
document.getElementById('root')
)
- 修改dist文件夹里面的index.html, 加上
<!DOCTYPE html><html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1"></head><body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
-
执行命令npm run build, 可以看到编译成功
-
用浏览器打开dist文件夹中的index.html, 可以看到界面上的hello world.
-
写一个demo组件:
src下新建app.js
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>Hello React bbbbbb ccccccc666666cccccccc!</div>
);
}
}
- 在index.js中引入:
import React,{Component} from 'react'
import {render} from 'react-dom'
import App from './app'
render(
<div>Hello Reactdfsf<App></App></div>,
document.getElementById('app')
)
-
重新打包,界面上出现app.js中的内容。
-
使用webpack-dev-server热加载
安装
npm i webpack-dev-server -D
修改webpack.config.js, 增加devServer
devServer: {
inline: true,
port: '8081',
contentBase: './dist'
},
修改package.json, script下增加dev
"dev": "webpack-dev-server --open --config=webpack/webpack.config.js --color --mode development",
命令分为几段:webpack-dev-server --open 表示打开热加载
–config=webpack/webpack.config.js 表示执行webpack.config.js文件
–color 表示终端输出带颜色
----mode development 开发模式
使用npm run dev启动项目,会自动打开网页,修改app.js或者index.js中的内容,可以看到界面上内容刷新。
- 安装样式加载器
react自带的样式书写方法有声明字面量方式和内嵌方式,引入其他样式文件使用import。
为了让样式书写更方便
安装样式加载器
npm install style-loader css-loader --save
webpack.config.js增加配置
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
},
{ // 增加
test: /\.css/,
loader: 'style-loader!css-loader'
}
]
},
app.js文件里加上className
<div style={{color:'red'}} className="cont">Hello React bbbbbb ccccccc666666cccccccc!</div>
在根目录下新建css文件夹,新建app.js文件,随便写几个样式
.cont{
font-size: 20px;
}
重启可以看到界面上样式更改。
以上对样式的处理,会是内联方式引入
<style>
.cont {
font-size: 20px;
}
</style>
- 接下来我们来把引入方式改成外联link.
为了加载速度更快会把CSS和JS打包到不同的文件中,开发的时候是不需要单独编译CSS文件的。如果你在开发环境加了这个,又配置了热更新,那么你会发现CSS发生变化时热更新用不了了。
所以将之前webpack.config.js文件名改为webpack.config.dev.js。
新建文件webpack.config.prod.js作为生产环境配置。将dev.js中的内容复制过来再进行修改。
如果是webpack 4 以下的版本可以使用extract-text-webpack-plugin。配置如下:
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
plugins: [
new ExtractTextWebpackPlugin("bundle.css")
],
如果是webpack 4 以上版本,官方推荐使用mini-css-extract-plugin。配置如下:
安装:npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
module: {
rules: [
// {
// test: /\.css/,
// loader: 'style-loader!css-loader?modules'
// }
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
}
打包后访问dist文件夹下的index.html,样式以外联引入了。然后npm run dev
,开发环境下是内联引入。
如果需要使用到less或者sass,先安装模块
npm i less less-loader -D
在webpack.config.prod.js文件中修改这段代码
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader","less-loader"
]
}
在webpack.config.dev.js文件中修改这段代码
{
test: /\.(css|less)$/,
use: ["style-loader","css-loader","less-loader"],
exclude: /node_modules/
}
修改app.css为app.less
@blue:blue;
.cont{
font-size: 20px;
color:@blue;
}
开发环境生产环境分别启动后,可见样式生效
- 加载图片资源
安装处理静态资源的加载器,url-loader对于指定大小以下的图片会转成base64
npm install file-loader url-loader --save
…dev.js增加
{
test:/\.(jpg|jpeg|png|pneg|gif|bmp)$/,
exclude: /node_modules/,
use:[{
loader:'url-loader',
options:{
limit: 500, //是把小于500B的文件打成Base64的格式,写入JS
name: 'image/[name].[ext]',
}
}]
},
…prod.js增加
{
test:/\.(jpg|jpeg|png|pneg|gif|bmp)$/,
use:[{
loader:'url-loader',
options:{
limit:1000, // 表示小于1000kb的图片转为base64
name: 'image/[name].[ext]',
publicPath:'./' //定义输出的图片文件夹
}
}]
}
此时可以看到开发环境下图片可以引入,并且打包后独立生成了image文件夹
但是细心的朋友会发现,当html文件中使用img,css中使用background引入图片时,项目打包后图片地址会有一个不对。此时我们仔细查看html中的图片路径和css文件中的图片路径。发现原因是:
大概目录:
- css
- index.css
- img
- 1.png
- index.html
css访问图片地址为…/img/1.png
html访问呢图片地址为./img/1.png
所以我们需要单独为css设置路径,而css是使用MiniCssExtractPlugin工具打包,所以将prod.js文件修改如下:
{
test: /\.(css|less)$/,
use: [
{
loader:MiniCssExtractPlugin.loader,
options:{
publicPath: '../'
}
},
"css-loader",
"less-loader"
]
},
{
test:/\.(jpg|jpeg|png|pneg|gif|bmp)$/,
use:[{
loader:'url-loader',
options:{
limit:500, // 表示小于500kb的图片转为base64
name: 'image/[name].[ext]',
// publicPath : './'
}
}]
}
以上配置已经满足基本开发,但是还需要考虑web性能优化,比如css冗余处理,ssr服务端渲染。
错误信息
1.Error: Cannot find module ‘webpack/schemas/WebpackOptions.json’
没有安装webpack-cli
npm install --save-dev webpack-cli
2.Error: Cannot find module ‘@babel/core’
babel-loader@8 requires Babel 7.x (the package ‘@babel/core’). If you’d like to use Babel 6.x (‘babel-core’), you should install ‘babel-loader@7’.
使用8.x的 babel-loader就要配套使用7.x的@babel/core,使用7.x的babel-loader就要配套使用6.x的babel-core。
注意到这里@babel/core和babel-core的改变。
"devDependencies": {
"@babel/core": "^7.1.0",
"babel-loader": "^8.0.2",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
}
3.Module build failed (from ./node_modules/_babel-loader@7.1.5@babel-loader/lib/index.js):
SyntaxError: C:\Users******.babelrc: Error while parsing JSON - Unexpected EOF at line 1 column 2 of the JSON5 data. Still to read: “”
或者:
Module build failed (from ./node_modules/_babel-loader@8.0.6@babel-loader/lib/index.js):
SyntaxError: C:\Users******\Desktop\myproject\react******.babelrc: Error while parsing config - JSON5: invalid end of input at 1:1
.babelrc文件配置有问题,参考配置
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": []
}
4.Module build failed (from ./node_modules/_babel-loader@8.0.6@babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In C:\Users\***\node_modules\babel-preset-es2015\lib\index.js
之前错误的使用了废弃的babel-preset-es2015(已更新为@babel/preset-env),在js配置文件module中有配置,需要改成:
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
5.热加载没有效果
是否是没有加 contentBase: ‘./dist’ 默认目录