webpack4 + react 搭建多頁(yè)面應(yīng)用示例
webpack 升級(jí)到4之后還沒(méi)好好的同步一個(gè)可實(shí)用的webpack架子,接下來(lái)用webpack4來(lái)搭建一個(gè)簡(jiǎn)單的react的多界面應(yīng)用,廢話不說(shuō) 直接擼碼
創(chuàng)建工程
$ mkdir demo && cd demo $ npm init -y
webpack 配置
安裝react + babel 依賴
$ npm i -S react@16.3.0 react-dom@16.3.0 $ npm i -D webpack@4.4.1 webpack-cli@2.0.13 webpack-dev-server@3.1.1 webpack-merge@4.1.2 babel-cli@6.26.0 babel-preset-env@1.6.1 babel-preset-react@6.24.1 babel-preset-react-hmre@1.1.1 babel-loader@7.1.4 file-loader@1.1.11 url-loader@1.0.1
webpack.base.conf.js(config -> webpack)
const entry = require("./webpack.entry.conf");
const newEntry = {};
for (let name in entry) {
newEntry[name] = entry[name][0]
}
let config = {
entry: newEntry,
resolve: {
extensions: [".js", ".json", ".jsx", ".css", ".pcss"],
}
};
module.exports = config;
webpack.dev.conf.js
const webpack = require('webpack');//引入webpack
const opn = require('opn');//打開(kāi)瀏覽器
const merge = require('webpack-merge');//webpack配置文件合并
const path = require("path");
const baseWebpackConfig = require("./webpack.base.conf");//基礎(chǔ)配置
const webpackFile = require("./webpack.file.conf");//一些路徑配置
const eslintFormatter = require('react-dev-utils/eslintFormatter');
let config = merge(baseWebpackConfig, {
/*設(shè)置開(kāi)發(fā)環(huán)境*/
mode: 'development',
output: {
path: path.resolve(webpackFile.devDirectory),
filename: 'js/[name].js',
chunkFilename: "js/[name].js",
publicPath: ''
},
optimization: {
runtimeChunk: {
name: 'manifest'
},
// 包拆分
splitChunks: {
cacheGroups: {
common: { // 項(xiàng)目的公共組件
chunks: "initial",
name: "common",
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
vendor: { // 第三方組件
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
}
}
},
plugins: [
/*設(shè)置熱更新*/
new webpack.HotModuleReplacementPlugin(),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: [
'babel-loader',
'cache-loader',
],
include: [
path.resolve(__dirname, "../../app"),
path.resolve(__dirname, "../../entryBuild")
],
exclude: [
path.resolve(__dirname, "../../node_modules")
],
},
{
test: /\.(css|pcss)$/,
loader: 'style-loader?sourceMap!css-loader?sourceMap!postcss-loader?sourceMap',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|ttf|eot|woff|woff2|svg|swf)$/,
loader: 'file-loader?name=[name].[ext]&outputPath=' + webpackFile.resource + '/'
},
{
test: /\.(js|jsx)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
// @remove-on-eject-begin
baseConfig: {
extends: [require.resolve('eslint-config-react-app')],
},
//ignore: false,
useEslintrc: false,
// @remove-on-eject-end
},
loader: require.resolve('eslint-loader'),
},
],
include: [
path.resolve(__dirname, "../../app")
],
exclude: [
path.resolve(__dirname, "../../node_modules")
],
}
]
},
/*設(shè)置api轉(zhuǎn)發(fā)*/
devServer: {
host: '0.0.0.0',
port: 8080,
hot: true,
inline: true,
contentBase: path.resolve(webpackFile.devDirectory),
historyApiFallback: true,
disableHostCheck: true,
proxy: [
{
context: ['/api/**', '/u/**'],
target: 'http://10.8.200.69:8080/',
secure: false
}
],
/*打開(kāi)瀏覽器 并打開(kāi)本項(xiàng)目網(wǎng)址*/
after() {
opn('http://localhost:' + this.port);
}
}
});
module.exports = config;
webpack.prod.conf.js
const path = require('path');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const baseWebpackConfig = require("./webpack.base.conf");
const webpackFile = require('./webpack.file.conf');
const entry = require("./webpack.entry.conf");
const webpackCom = require("./webpack.com.conf");
let config = merge(baseWebpackConfig, {
/*設(shè)置生產(chǎn)環(huán)境*/
mode: 'production',
output: {
path: path.resolve(webpackFile.proDirectory),
filename: 'js/[name].[chunkhash:8].js',
chunkFilename: "js/[name]-[id].[chunkhash:8].js",
},
optimization: {
//包清單
runtimeChunk: {
name: "manifest"
},
//拆分公共包
splitChunks: {
cacheGroups: {
common: { //項(xiàng)目公共組件
chunks: "initial",
name: "common",
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
vendor: { //第三方組件
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
}
}
},
plugins: [
// extract css into its own file
new ExtractTextPlugin('css/[name].[md5:contenthash:hex:8].css'),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: {
discardComments: {removeAll: true},
// 避免 cssnano 重新計(jì)算 z-index
safe: true
},
canPrint: true
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: [
'babel-loader',
],
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(css|pcss)$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader!postcss-loader"
})
},
{
test: /\.(png|jpg|gif|ttf|eot|woff|woff2|svg)$/,
loader: 'url-loader?limit=8192&name=[name].[hash:8].[ext]&publicPath=' + webpackFile.resourcePrefix + '&outputPath=' + webpackFile.resource + '/'
},
{
test: /\.swf$/,
loader: 'file?name=js/[name].[ext]'
}
]
}
});
let pages = entry;
for (let chunkName in pages) {
let conf = {
filename: chunkName + '.html',
template: 'index.html',
inject: true,
title: webpackCom.titleFun(chunkName,pages[chunkName][1]),
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunks: ['manifest', 'vendor', 'common', chunkName],
hash: false,
chunksSortMode: 'dependency'
};
config.plugins.push(new HtmlWebpackPlugin(conf));
}
/* 清除 dist */
config.plugins.push(new CleanWebpackPlugin([webpackFile.proDirectory], {root: path.resolve(__dirname, '../../'), verbose: true, dry: false}));
/* 拷貝靜態(tài)資源 */
copyArr.map(function (data) {
return config.plugins.push(data)
});
module.exports = config;
構(gòu)建多界面
整體架構(gòu)搭建起來(lái)之后
app -> component
$ mkdir demo && cd demo
$ touch Index.jsx
import React from 'react';
class Index extends React.Component {
render() {
return (
<div className="demo">
寫個(gè)demo
</div>
);
}
}
export default Index;
在config -> entry
module.exports = [
{
name: 'index',
path: 'index/Index.jsx',
title: '首頁(yè)',
keywords: '首頁(yè)',
description: '首頁(yè)'
},
{
name: 'demo',
path: 'demo/Index.jsx',
title: 'demo',
keywords: 'demo',
description: 'demo'
},
{
name: 'demo1',
path: 'demo1/Index.jsx',
title: 'demo1',
keywords: 'demo1',
description: 'demo1'
}
];
然后直接執(zhí)行 npm run create-dev 就會(huì)在devBuild 和 entryBuild 中添加一個(gè)新的demo.html 和 demo.js
package.json
{
"name": "webpack_es6",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors --profile --config config/webpack/webpack.dev.conf.js",
"entry": "node config/entry/entryBuild.js",
"devBuildHtml": "node config/webpack/webpack.devBuildHtml.conf.js",
"create-dev": "npm run entry && npm run devBuildHtml",
"build": "BABEL_ENV=production && webpack --progress --colors --config config/webpack/webpack.prod.conf.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^16.3.0",
"react-dom": "^16.3.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-eslint": "^8.2.2",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-react-hmre": "^1.1.1",
"cache-loader": "^1.2.2",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.1",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"eslint-config-react-app": "^2.1.0",
"eslint-loader": "^2.0.0",
"eslint-plugin-flowtype": "^2.46.1",
"eslint-plugin-import": "^2.10.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.7.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file": "^0.2.2",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.1.0",
"optimize-css-assets-webpack-plugin": "^4.0.0",
"postcss-cssnext": "^3.1.0",
"postcss-loader": "^2.1.3",
"precss": "^3.1.2",
"react-dev-utils": "^5.0.0",
"style-loader": "^0.20.3",
"url-loader": "^1.0.1",
"webpack": "^4.4.1",
"webpack-cli": "^2.0.13",
"webpack-dev-server": "^3.1.1",
"webpack-merge": "^4.1.2"
},
"eslintConfig": {
"extends": "react-app",
"rules": {
"import/no-webpack-loader-syntax": 0,
"no-script-url": 0,
"jsx-a11y/href-no-hash": 2
}
}
}
開(kāi)發(fā)環(huán)境小技巧
在開(kāi)發(fā)環(huán)境添加cache-loader 可以提升在開(kāi)發(fā)環(huán)境的編譯速度
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 詳解使用WebPack搭建React開(kāi)發(fā)環(huán)境
- 基于Webpack4和React hooks搭建項(xiàng)目的方法
- 基于webpack4.X從零搭建React腳手架的方法步驟
- Webpack 4.x搭建react開(kāi)發(fā)環(huán)境的方法步驟
- 基于webpack4搭建的react項(xiàng)目框架的方法
- 從零開(kāi)始搭建webpack+react開(kāi)發(fā)環(huán)境的詳細(xì)步驟
- 使用webpack搭建react開(kāi)發(fā)環(huán)境的方法
- 手動(dòng)用webpack搭建第一個(gè)ReactApp的示例
- 詳解基于webpack搭建react運(yùn)行環(huán)境
- 使用webpack5從0到1搭建一個(gè)react項(xiàng)目的實(shí)現(xiàn)步驟
相關(guān)文章
React中setState同步異步場(chǎng)景的使用
本文主要介紹了React中setState同步異步場(chǎng)景的使用,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱
這篇文章主要介紹了React?Hooks?之?useReducer?逃避deps后增加組件渲染次數(shù)的陷阱詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
react實(shí)現(xiàn)一個(gè)優(yōu)雅的圖片占位模塊組件詳解
這篇文章主要給大家介紹了關(guān)于react如何實(shí)現(xiàn)一個(gè)還算優(yōu)雅的占位模塊圖片組件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
每天學(xué)習(xí)一個(gè)hooks?useMount
這篇文章主要為大家介紹了每天學(xué)習(xí)一個(gè)hooks?useMount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
react項(xiàng)目升級(jí)報(bào)錯(cuò),babel報(bào)錯(cuò),.babelrc配置兼容等問(wèn)題及解決
這篇文章主要介紹了react項(xiàng)目升級(jí)報(bào)錯(cuò),babel報(bào)錯(cuò),.babelrc配置兼容等問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
React項(xiàng)目中使用Redux的?react-redux
這篇文章主要介紹了React項(xiàng)目中使用Redux的?react-redux,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
每天一個(gè)hooks學(xué)習(xí)之useUnmount
這篇文章主要為大家介紹了每天一個(gè)hooks學(xué)習(xí)之useUnmount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
用react實(shí)現(xiàn)一個(gè)簡(jiǎn)單的scrollView組件
這篇文章主要給大家介紹一下如何用 react 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 scrollView組件,文中有詳細(xì)的代碼示例,具有一定的參考價(jià)值,需要的朋友可以參考下2023-07-07

