新建一個項目react-initcss
mkdir react-init
cd react-init
複製代碼
初始化html
yarn init -y
# 或
npm init -y
複製代碼
webpack4的安裝須要安裝兩個,一個是webpack,另外就是webpack-clihtml5
yarn add webpack webpack-cli -D
# 或
npm i webpack webpack-cli -D
複製代碼
在項目根目錄下面建立config目錄,並在該目錄裏面建3個配置文件,分別是:node
webpack.base.conf.js —— 共有配置react
webpack.dev.conf.js —— 開發環境配置webpack
webpack.prod.conf.js —— 生產環境配置web
由於使用了公共的配置項,因此爲了可以使用公共項,須要引入另一個庫,安裝以下:npm
yarn add webpack-merge -D
# 或
npm i webpack-merge -D
複製代碼
在webpack.base.conf.js裏面寫入:json
const path = require('path');
const DIST_PATH = path.resolve(__dirname, '../dist');
const APP_PATH = path.resolve(__dirname, '../src');
module.exports = {
entry: {
app: APP_PATH+'/index.js'
},
output: {
filename: "js/[name].[chunkhash].js",
path: DIST_PATH
},
resolve: {
extensions: [".js", ".jsx", ".less"],
alias: {
"@": APP_PATH
}
},
}
複製代碼
在webpack.dev.conf.js裏面寫入:瀏覽器
const path = require("path");
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
module.exports = merge(baseWebpackConfig, {
mode: "development",
output: {
filename: "js/[name].[hash:16].js"
},
devtool: "inline-source-map",
});
複製代碼
在webpack.prod.conf.js裏面寫入:
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
module.exports = merge(baseWebpackConfig, {
mode: "production",
});
複製代碼
在根目錄下面建立src目錄,而後建立index.js文件,做爲整個項目的入口文件,建立App.jsx文件,做爲react項目的根組件;
在根目錄下面建立public目錄,而後建立index.html文件,做爲整個單頁項目的模板文件;
index.html內容以下:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- <title><%= htmlWebpackPlugin.options.title %></title> -->
<title>React-Init</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製代碼
在package.json裏面,添加命令行腳本:
"scripts": {
"build": "webpack --config config/webpack.prod.conf.js"
}
複製代碼
yarn add react react-dom
# 或
npm i react react-dom -S
複製代碼
修改src/App.jsx文件以下:
import React, { Component } from "react";
class App extends Component {
render() {
return (
<h1>Hello React</h1>
);
}
}
export default App;
複製代碼
修改src/index.js文件以下:
import React from "react";
import ReactDom from "react-dom";
import App from "./App";
ReactDom.render(<App />, document.getElementById("root")); 複製代碼
爲了使ES6的模塊化被支持以及可以轉爲瀏覽器識別的ES5代碼,和JSX格式解析,必須引入對應的babel和babel插件,安裝以下:
yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react -D
# 或
npm i babel-loader @babel/core @babel/preset-env @babel/preset-react -D
複製代碼
配置babel:
在webpack.base.conf.js裏面
module.exports = {
...
resolve: {
extensions: [".js", ".jsx", ".less"],
alias: {
"@": APP_PATH
}
},
// 如下是添加的內容
module: {
rules: [
{
test: /\.jsx?$/,
use: 'babel-loader',
include: APP_PATH
},
]
}
}
複製代碼
而後在根目錄新建.babelrc文件,內容以下:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
複製代碼
安裝html-webpack-plugin插件:
yarn add html-webpack-plugin -D
# 或
npm i html-webpack-plugin -D
複製代碼
這個能夠將生成的JS文件自動加載到html的script標籤內去,能夠自定義html模板,具體看其在npm網站上的文檔。
給webpack.prod.conf.js增長配置內容以下
...
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(baseWebpackConfig, {
mode: "production",
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
})
]
});
複製代碼
此時,能夠進行build了,運行
yarn build
# 或
npm run build
複製代碼
若是沒有報錯,且根目錄下生成dist目錄,則表示以前的配置基本上正確了
webpack優化
生產過程當中,可使用clean-webpack-plugin對dist文件夾先進行清理:
yarn add clean-webpack-plugin -D
複製代碼
而後在webpack.prod.conf.js裏面增長以下內容:
...
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
...
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "public/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
})
]
...
複製代碼
yarn add webpack-dev-server -D
複製代碼
在webpack.dev.conf.js裏面添加:
...
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
module.exports = merge(baseWebpackConfig, {
...
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html",
inject: "body",
minify: {
html5: true
},
hash: false
}),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
port: 3000,
contentBase: path.join(__dirname, "../public"),
compress: true,
historyApiFallback: true,
hot: true,
https: false,
noInfo: true,
open: true,
proxy: {}
}
});
複製代碼
而後在package.json的腳本里面:
"scripts": {
"build": "webpack --config config/webpack.prod.conf.js",
"dev": "webpack-dev-server --inline --progress --config config/webpack.dev.conf.js"
}
複製代碼
執行
yarn dev
# 或
npm run dev
複製代碼
便可在打開的瀏覽器裏面進行訪問,地址爲localhost:3000
使用webpack咱們能夠在js裏面導入css或less文件,可是必須使用相應的loader才能進行處理。
yarn add css-loader mini-css-extract-plugin less less-loader postcss-loader autoprefixer -D
複製代碼
在webpack.base.conf.js裏面添加
...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
module.exports = {
...
module: {
rules: [
{
test: /\.jsx?$/,
use: "babel-loader",
include: APP_PATH
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true // 使支持css modules
}
}
]
},
{
test: /\.less$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true
}
},
{
loader: "postcss-loader",
options: {
plugins: [require("autoprefixer")()]
}
},
{
loader: "less-loader",
options: {
modifyVars: {
// 自定義的主題內容寫在這裏
}
}
}
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
ignoreOrder: false
})
]
};
複製代碼
爲了使autoprefixer生效,須要在package.json裏面添加以下內容:
"browserslist": [
"last 4 version",
"> 1%",
"maintained node versions",
"not dead"
]
複製代碼
安裝loader:
yarn add file-loader url-loader -D
複製代碼
在webpack.base.conf.js裏面添加:
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|jpeg|bmp|webp)$/,
use: [
{
loader: "url-loader",
options: {
publicPath: "/",
name: "images/[name].[ext]",
limit: 512
}
}
]
},
{
test: /\.(woff|svg|eot|woff2|tff)$/,
use: "file-loader",
exclude: /node_modules/
}
]
},
...
};
複製代碼
到這裏,基本上所須要的配置都已經OK了,那麼所有的配置文件內容以下所示:
webpack.base.conf.js
const path = require("path");
const DIST_PATH = path.resolve(__dirname, "../dist");
const APP_PATH = path.resolve(__dirname, "../src");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
app: APP_PATH + "/index.js"
},
output: {
filename: "js/[name].[chunkhash].js",
path: DIST_PATH
},
module: {
rules: [
{
test: /\.jsx?$/,
use: "babel-loader",
include: APP_PATH
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true
}
}
]
},
{
test: /\.less$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true
}
},
{
loader: "postcss-loader",
options: {
plugins: [require("autoprefixer")()]
}
},
{
loader: "less-loader",
options: {
modifyVars: {
// 自定義的主題內容寫在這裏
}
}
}
]
},
{
test: /\.(png|jpg|gif|jpeg|bmp|webp)$/,
use: [
{
loader: "url-loader",
options: {
publicPath: "/",
name: "images/[name].[ext]",
limit: 512
}
}
]
},
{
test: /\.(woff|svg|eot|woff2|tff)$/,
use: "file-loader",
exclude: /node_modules/
}
]
},
resolve: {
extensions: [".js", ".jsx", ".less"],
alias: {
"@": APP_PATH
}
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
ignoreOrder: false
})
]
};
複製代碼
webpack.dev.conf.js
const path = require("path");
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
module.exports = merge(baseWebpackConfig, {
mode: "development",
output: {
filename: "js/[name].[hash:16].js"
},
devtool: "inline-source-map",
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html",
inject: "body",
minify: {
html5: true
},
hash: false
}),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
port: 3000,
contentBase: path.join(__dirname, "../public"),
compress: true,
historyApiFallback: true,
hot: true,
https: false,
noInfo: true,
open: true,
proxy: {}
}
});
複製代碼
webpack.prod.conf.js
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = merge(baseWebpackConfig, {
mode: "production",
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "public/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
})
]
});
複製代碼
.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
複製代碼
package.json
{
"name": "react-init",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack --config config/webpack.prod.conf.js",
"dev": "webpack-dev-server --inline --progress --config config/webpack.dev.conf.js"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/plugin-transform-runtime": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"autoprefixer": "^9.6.1",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"file-loader": "^4.2.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.8.0",
"postcss-loader": "^3.0.0",
"url-loader": "^2.1.0",
"webpack": "^4.39.1",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack-merge": "^4.2.1"
},
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
"browserslist": [
"last 4 version",
"> 1%",
"maintained node versions",
"not dead"
]
}
複製代碼
整個項目的目錄結構爲:
react-init
├── config
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── public
│ └── index.html
├── src
│ ├── App.jsx
│ ├── app.less
│ ├── assets
│ │ └── 01.jpeg
│ └── index.js
├── .babelrc
├── package.json
└── yarn.lock
複製代碼