yarn add create-react-app -global
npx create-react-app my-app
複製代碼
安裝:javascript
yarn add webpack webpack-cli webpack-dev-server
複製代碼
在package.json增長css
"scripts": {
"dev": "webpack-dev-server --mode development",
"build": "webpack --mode production",
},
# yarn dev 去啓動本地server
# yarn build 去生成生產代碼
複製代碼
生成配置文件:html
touch webpack.config.js
複製代碼
在webpack.config.js
增長java
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
// path function
const resolve = src => {
return path.resolve(__dirname, src);
};
module.exports = (env, argv) => {
//argv 裏面的 mode 分別是以前執行命令的的,development production
// 傳遞給 babel.config.js
process.env.NODE_ENV = argv.mode;
return ({
entry: {
"login": "./src/login",
"index": "./src/index",
},
output: {
path: resolve("cdn"),
filename: 'js/[name].[hash:8].js',
publicPath: '/',
},
//解析 jsx
rules: [{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
}],
plugins:[
// 生成最終須要的html模板
new HtmlWebpackPlugin({
title: "Login",
template: resolve("public/index.html"),
filename: "login.html",
hash: true,//增長hash
minify:true,//壓縮html代碼
chunks: ['login'],
favicon: resolve("public/favicon.ico")
}),
new HtmlWebpackPlugin({
title: "Index",
template: resolve("public/index.html"),
filename: "index.html",
hash: true,
minify: true,
chunks: ['index'],
favicon: resolve("public/favicon.ico")
})
]
})
}
複製代碼
此時還須要配置 babel7,把 ES6\7轉化爲瀏覽器直接解析的語法;node
webpack 4: transpiling Javascript ES6 with Babel 7react
babel-loader把ES6甚至更高的版本,編譯成ES5,這樣瀏覽器就能解析了。webpack
babel core babel loader babel preset env for compiling Javascript ES6 code down to ES5web
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react
複製代碼
下一步,咱們生成一個babel.config.js配置文件shell
touch babel.config.js
複製代碼
babel.config.js
json
在這裏能夠除無用的 console.log()
來減小文件的體積。
const removeConsolePlugin = [];
console.log("babel", process.env.NODE_ENV)
//移除console
if (process.env.NODE_ENV == "production") {
console.log("====remove-console=====");
removeConsolePlugin.push([
"transform-remove-console",
{
"exclude": ["error", "warn"]
}
]);
}
module.exports = {
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"targets": {
"browsers": [
"last 2 Chrome versions",
"last 2 Firefox versions",
"last 2 Safari versions",
"last 2 iOS versions",
"last 1 Android version",
"last 1 ChromeAndroid version",
"ie 11"
]
}
}
],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
...removeConsolePlugin
]
}
複製代碼
這個時候yarn dev
,咱們啓動本地server,應該是成功的了。
resolve: {
// 別名
alias: {
"@": resolve('src'),
"@c": resolve('src/components'),
"@less": resolve('src/less'),
"@util": resolve('src/utils'),
"@assets": resolve('src/assets'),
},
// 自動添加後綴
extensions: ['.jsx', '.js', '.less']
}
複製代碼
devServer: {
port: 3001,
open: true,
hot: true,
compress: true,
contentBase: path.join(__dirname, './'),
noInfo: false,
overlay: {
warnings: true,
errors: true
},
proxy: {
'/api': {
target: 'http://****',
changeOrigin: true,
},
}
}
複製代碼
// webpack4 使用 mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 分離css
# plugins 增長
plugins.push(new MiniCssExtractPlugin({
// Options similar to the same options webpackOptions.output
// all options are optional
filename: 'css/[name].[hash:8].css',
chunkFilename: 'css/[name].[hash:8].css',
ignoreOrder: false
}));
#rules 增長
rules:[
{
test: /\.less$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
"less-loader"
]
// webpack4 廢棄
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: [
// 'css-loader',
// "less-loader"
// ]
// })
}
]
複製代碼
{
test: /\.(png|jpg|svg|gif|ico)?$/,
use: [{
loader: 'url-loader',
options: { // 這裏的options選項參數能夠定義多大的圖片轉換爲base64
fallback: "file-loader",
limit: 10 * 1024, // 表示小於10kb的圖片轉爲base64,大於10kb的是路徑
outputPath: 'images', //定義輸出的圖片文件夾
name: '[name].[contenthash:8].[ext]'
}
}]
}
複製代碼
// 去除重複的 less, 好比 common.less裏面的內容
plugins.push(new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
}
}
],
},
canPrint: true
}));
複製代碼
八、提取各個模塊的公共代碼
optimization: {
splitChunks: {
// 靜態資源緩存
// test, priority and reuseExistingChunk can only be configured on cache group level.
cacheGroups: {
// 提取 node_modules 裏面依賴的代碼
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'chunk-vendors',
chunks: 'all',
minChunks: 2, //2個共享以及以上都提取
priority: -10 //優先級
},
// 提出每一個模塊公共的代碼
commons: {
name: 'chunk-commons',
test: /\.js$/,
chunks: 'initial',
minChunks: 2, //兩個共享以及以上都提取,
minSize: 0,
priority: -20, //優先級
reuseExistingChunk: true
},
css: {
name: 'css-commons',
test: /\.less$/,
minChunks: 2,
minSize: 0,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
}
}
},
// I pull the Webpack runtime out into its own bundle file so that the
// contentHash of each subsequent bundle will remain the same as long as the
// source code of said bundles remain the same.
runtimeChunk: "single"
}
複製代碼
所有代碼以下:
/** * webpack 4 config * @author master2011zhao@gmail.com * @Date 20190910 */
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
// webpack4 使用 mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// extract 被廢棄
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
// clean project
const {
CleanWebpackPlugin
} = require("clean-webpack-plugin");
// 壓縮css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// notifier
const WebpackBuildNotifierPlugin = require('webpack-build-notifier');
// path function
const resolve = src => {
return path.resolve(__dirname, src);
};
module.exports = (env, argv) => {
const isProduction = argv.mode === "production";
console.log("isProduction", isProduction);
// 傳遞給 babel.config.js
process.env.NODE_ENV = argv.mode;
// console.log(process.env.NODE_ENV);
let plugins = [];
// 生成模板
let HtmlTemplates = [];
// 生產環境
if (isProduction) {
// 清理項目, 清理不乾淨,須要使用 rm.sh
plugins.push(new CleanWebpackPlugin({
dry: false,
verbose: true,
}));
// 構建完成提醒
plugins.push(new WebpackBuildNotifierPlugin({
title: "react project build",
suppressSuccess: true,
suppressWarning: false,
messageFormatter: function () {
return "build completely"
}
}));
// 分離css
// plugins.push(new ExtractTextPlugin('css/[name].[hash:8].css'));
plugins.push(new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: 'css/[name].[hash:8].css',
chunkFilename: 'css/[name].[hash:8].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}));
// 去除重複的 less, 好比 common
plugins.push(new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
}
}
],
},
canPrint: true
}));
// 公共提取的chunk
const commonChunks = ["chunk-vendors", "runtime", "chunk-commons", "css-commons"];
const minify = {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
// 生成模板
HtmlTemplates = [
new HtmlWebpackPlugin({
title: "Login",
template: resolve("public/index.html"),
filename: "login.html",
hash: true,
minify,
chunks: [...commonChunks, 'login'],
favicon: resolve("public/favicon.ico")
}),
new HtmlWebpackPlugin({
title: "Index",
template: resolve("public/index.html"),
filename: "index.html",
hash: true,
minify,
chunks: [...commonChunks, 'index'],
favicon: resolve("public/favicon.ico")
})
]
} else {
// 生成模板
HtmlTemplates = [
new HtmlWebpackPlugin({
title: "Login",
template: resolve("public/index.html"),
filename: "login.html",
favicon: resolve("public/favicon.ico"),
chunks: ['login'], //指定入口
}),
new HtmlWebpackPlugin({
title: "Index",
template: resolve("./public/index.html"),
filename: "index.html",
favicon: resolve("public/favicon.ico"),
chunks: ['index'], //指定入口
})
]
}
return {
entry: {
"login": "./src/login",
"index": "./src/index",
},
output: {
path: resolve("cdn"),
filename: 'js/[name].[hash:8].js',
publicPath: '/',
},
devServer: {
port: 3001,
open: true,
hot: true,
compress: true,
contentBase: path.join(__dirname, './'),
noInfo: false,
overlay: {
warnings: true,
errors: true
},
proxy: {
'/api': {
target: 'http://*****:8093',
changeOrigin: true,
},
}
},
resolve: {
// 別名
alias: {
"@": resolve('src'),
"@c": resolve('src/components'),
"@less": resolve('src/less'),
"@util": resolve('src/utils'),
"@assets": resolve('src/assets'),
},
// 自動添加後綴
extensions: ['.jsx', '.js', '.less']
},
module: {
rules: [{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.less$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
"less-loader"
]
// webpack4 廢棄
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: [
// 'css-loader',
// "less-loader"
// ]
// })
},
{
test: /\.(png|jpg|svg|gif|ico)?$/,
use: [{
loader: 'url-loader',
options: { // 這裏的options選項參數能夠定義多大的圖片轉換爲base64
fallback: "file-loader",
limit: 10 * 1024, // 表示小於10kb的圖片轉爲base64,大於10kb的是路徑
outputPath: 'images', //定義輸出的圖片文件夾
name: '[name].[contenthash:8].[ext]'
}
}]
},
// {
// test: /\.html$/,
// use: [{
// loader: "html-loader",
// options: {
// minimize: true,
// removeComments: true,
// collapseWhitespace: true
// }
// }]
// }
]
},
plugins: [
...plugins,
...HtmlTemplates
],
optimization: {
splitChunks: {
// 靜態資源緩存
// test, priority and reuseExistingChunk can only be configured on cache group level.
cacheGroups: {
// 提取 node_modules 裏面依賴的代碼
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'chunk-vendors',
chunks: 'all',
minChunks: 2, //2個共享以及以上都提取
priority: -10 //優先級
},
// 提出每一個模塊公共的代碼
commons: {
name: 'chunk-commons',
test: /\.js$/,
chunks: 'initial',
minChunks: 2, //兩個共享以及以上都提取,
minSize: 0,
priority: -20, //優先級
reuseExistingChunk: true
},
css: {
name: 'css-commons',
test: /\.less$/,
minChunks: 2,
minSize: 0,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
}
}
},
// I pull the Webpack runtime out into its own bundle file so that the
// contentHash of each subsequent bundle will remain the same as long as the
// source code of said bundles remain the same.
runtimeChunk: "single"
}
};
}
複製代碼