- 热更新还没做
- devServer Ajax跨域没配置
其他的差不多完成了。
package.json
{
"name": "demo1",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --config webpack.dev.js",
"server": "node server.js",
"dev": "set NODE_ENV=development && npm start",
"build": "set NODE_ENV=production && webpack --config webpack.prod.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.4.3",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
"superagent": "^5.0.2"
},
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.4.3",
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"autoprefixer": "^9.5.1",
"babel-loader": "^8.0.5",
"clean-webpack-plugin": "^2.0.1",
"css-loader": "^2.1.0",
"express": "^4.16.4",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^0.6.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^3.0.0",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^1.2.3",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.1",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"webpack-merge": "^4.2.1"
}
}
webpack.common.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let isModeDev = process.env.NODE_ENV.trim() === "development";
let srcPath = "src";
console.log('webpack.common.js NODE_ENV:'+ process.env.NODE_ENV + typeof process.env.NODE_ENV + isModeDev);
module.exports = {
entry: {
// output的name变量值就是main
// 打包后的css,js命名时的[name]指的都是main
main: './'+srcPath+'/index.jsx'
},
plugins: [
// 分离样式文件,否则所有的样式都会以style标签的形式直接插入head标签中
new MiniCssExtractPlugin({
filename: isModeDev ? '[name].css' : '[name].[hash:5].css',
chunkFilename: isModeDev ? '[id].css' : '[id].[hash:5].css',
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: __dirname + '/'+srcPath+'/index.html'
})
],
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js', // 决定非入口 chunk 的名称
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(sa|sc|le|c)ss$/,
use: [
// 分离样式文件, 而不是使用style-loader
MiniCssExtractPlugin.loader,
'css-loader',
{
loader:'postcss-loader',
options: {
plugins: [
require("autoprefixer")({
browsers : ['last 10 versions']//必须设置支持的浏览器才会自动添加添加浏览器兼容
})
]
}
}
]
},
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader'
},
// 不希望babel处理的 node_modules 目录下的文件
// UglifyJsPlugin不能压缩es6,如果过滤这个目录,
// 可能会导致node_modules里面的es6代码不能转换导致压缩报错
// exclude: '/node_modules/'
},
{
test: /\.(png|svg|jpg|gif)$/,
use:[{
loader:'file-loader',
options:{ // 这里的options选项参数可以定义多大的图片转换为base64
limit:50000, // 表示小于50kb的图片转为base64,大于50kb的是路径
name: '[hash:8].[name].[ext]',
publicPath:'./images',
outputPath: 'images/'
}
}]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use:[{
loader:'file-loader',
options:{
name: '[name].[ext]',
publicPath:'../fonts',
outputPath: 'fonts/'
}
}],
// 要排除 node_modules 目录下的
exclude: '/node_modules/'
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
]
},
resolve: {
extensions: ['.js', '.jsx','.json', '.vue'], //后缀名自动补全
}
};
webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
console.log('webpack.dev.js NODE_ENV:',process.env.NODE_ENV);
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
optimization: {
nodeEnv: typeof process.env.NODE_ENV === 'string' ? process.env.NODE_ENV.trim() : 'development'
},
devServer: {
contentBase: './',
port: '9999'
}
});
webpack.prod.js
const merge = require('webpack-merge');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const common = require('./webpack.common.js');
console.log('webpack.dev.js NODE_ENV:',process.env.NODE_ENV);
module.exports = merge(common, {
mode: 'production',
//devtool: 'source-map',
optimization: {
minimize: true, //取代 new UglifyJsPlugin(/* ... */)
// new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})压缩css样式
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
nodeEnv: typeof process.env.NODE_ENV === 'string' ? process.env.NODE_ENV.trim() : 'production'
}
});
server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}));
// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});
.babelrc
{
"presets": [
["@babel/preset-env",{
"targets": {
"browsers": ["> 1%", "last 2 versions"]
}
}],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime",{
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false
}
],
"@babel/plugin-syntax-dynamic-import"
]
}
貌似不用引入polyfill也可以。