在使用webpack 4.x版本构建前端项目的时候,遇到了一些坑点,这里做一下记录,详细内容见注释。
1、项目目录:
2、基本配置内容
webpack.base.config.js
'use strict';
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//用于在构建前清除dist目录中的内容
const CleanWebpackPlugin = require('clean-webpack-plugin');
let baseWebpackConfig = {
// 指定找入口文件所在文件夹
context: path.resolve(__dirname, '../src/test'), // 这里是我做test的一个单独文件夹
entry: './index.js',
output: {
// 打包出的文件名
filename: '[name].bundle.[hash:8].js',
// 打包出的文件输出路径
path: path.resolve(__dirname, '../dist'),
publicPath: "/" // 编译后模板文件地址
},
module: {
rules: [
{
test: /\.(js|jsx)$/i,
// use: ['babel-loader'],
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/,
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
plugins: ['react-hot-loader/babel'],
}
},
{
test: /\.(less|css)$/i,
use:['css-hot-loader',MiniCssExtractPlugin.loader,"css-loader","less-loader",{
loader: "postcss-loader",
options: {
ident: 'postcss',
plugins: () => [
require('autoprefixer')("last 100 versions")
]
}
}]
},
{
test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000, // 大于就用文件形式,小于就压缩成base64
name: 'img/[name].[hash:7].[ext]'
}
}]
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name].[hash:7].[ext]'
}
}]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]'
}
}]
}
]
},
plugins: [
//用于在构建前清除dist目录中的内容
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../'), // 根目录
verbose: true, // 开启在控制台输出信息
}),
// dist目录下生成html模板文件
new HtmlWebpackPlugin({
template: './index.html'
}),
// 样式代码分离
// new ExtractTextWebpackPlugin('styles.css'), // (webpack4废弃)
new MiniCssExtractPlugin({
filename: "[name].css", // **注意**这里不能使用hash,否则无法实现热跟新,如果有hash需要,可以开发环境和生产环境分开配置成[name].[chunkhash:8].css
chunkFilename: "[id].css" // 构建时生成的文件名
})
],
resolve: {
// 设置自动解析的扩展
extensions: ['.web.js', '.js', '.json', '.jsx', '.less', '.css'],
// 设置路径别名
alias: {
'@': path.resolve(__dirname, '../src/')
}
}
};
module.exports = baseWebpackConfig;
3、本地开发环境dev服务器配置
webpack.dev.config.js
'use strict';
const PORT = 3000;
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.config');
const OpenBrowserWebpackPlugin = require('open-browser-webpack-plugin');
let webpackDevServerConfig = {
mode: 'development',
// 入口配置
entry: [
'babel-polyfill', // 原生支持
'react-hot-loader/patch', // 局部更新
'./index.js'
],
devtool: 'cheap-module-source-map',
plugins: [
// 美化 console 输出
new webpack.NamedModulesPlugin(),
// 开启全局的模块热替换(HMR)
new webpack.HotModuleReplacementPlugin(),
// 编译完成在再浏览器打开项目
new OpenBrowserWebpackPlugin({url: `http://0.0.0.0:${PORT}`}), // {url: `http://localhost:${PORT}`}
// 编译时定义全局变量,用于判断执行环境 | 配合cross_env插件使用,它是运行跨平台设置和使用环境变量的脚本
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
],
devServer: {
// hot: true,
hotOnly: true, // 只热替换,不自动刷新
port: PORT,
inline: true, // 实时刷新
publicPath: baseWebpackConfig.output.publicPath,
host: '0.0.0.0',
// 是否关闭用于DNS重绑定的HTTP请求的host检查,它通常用于搭配 --host 0.0.0.0 使用,
// 因为你想要其它设备访问你本地的服务,但访问时是直接通过 IP 地址访问而不是 HOST 访问,所以需要关闭 HOST 检查。
disableHostCheck: true,
// 把项目根目录下的src目录设置成DevServer服务器的文件根目录
contentBase: path.resolve(__dirname, 'src'),
// 可以保证类似http://localhost:8080/aa的请求返回跟http://localhost:8080/一样的页面,
// 这样才能用同一个js根据路径的不同去往不同的路由
historyApiFallback: true
},
// dev环境打包的单个js文件可能过大,通过该方式取消警告
performance: {
hints: process.env.NODE_ENV === 'development' ? false : 'warning'
}
};
module.exports = merge(baseWebpackConfig, webpackDevServerConfig)
4、生产打包配置
webpack.build.config.js
'use strict';
const merge = require('webpack-merge');
const webpack = require('webpack');
const baseWebpackConfig = require('./webpack.base.config.js');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
let webpackBuildConfig = {
mode: 'production',
// 入口配置
entry: [
'babel-polyfill', // 浏览器原生支持
'react-hot-loader/patch', // 局部更新
'./index.js'
],
plugins: [
new UglifyJSPlugin({
sourceMap: true
}),
// 编译时定义全局变量,用于判断执行环境
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]
};
module.exports = merge(baseWebpackConfig, webpackBuildConfig);
5、package.json对scripts属性配置
核心代码:
"test": "echo \"Error: no test specified\" && exit 1",
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.config.js",
"build": "cross-env NODE_ENV=production webpack -p --config build/webpack.build.config.js"
package.json
6、test目录下的一些测试文件
<1>、 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test-html</title>
</head>
<body>
<div id="test"></div>
</body>
</html>
<2>、index.js
import React from 'react'
import ReactDom from 'react-dom'
import { AppContainer } from 'react-hot-loader';
import './style.less'
import bigImg from './imgs/big-test.png'
import smallImg from './imgs/small-test.png'
let html = <div className='wrapper'>
<h1 className='test'>hello webpack!</h1>
<span>16.4kb---></span><img src={bigImg} />
<span>6.09kb---></span><img src={smallImg} />
</div>
ReactDom.render(
<AppContainer>
{html}
</AppContainer>,
document.getElementById('test')
)
// HMR 接口
if (module.hot) {
// 实现热更新
module.hot.accept()
}
<3>、style.less
.wrapper{
display: flex;
flex-direction: column;
align-items: center;
.test{
border-radius: 5px;
flex: 1;
color: black
}
}
7、.babelrc的配置
{
"presets": [
[
"es2015",
{
"modules": false
}
],
"react",
"stage-0"
],
"plugins": [
"react-hot-loader/babel",
"transform-runtime"
]
}