开发时的配置说明
const path = require('path');
/**
* 但是你可能发现了,网页打开报错了~因为你dist/index.html里面引用js名字还是bundle.js老名字啊,改成新的名字就可以啦。
啊~那岂不是我每次编译打包,都得去改一下js名字?
使用 HtmlWebpackPlugin 插件处理
*/
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
/**
* 提取公共代码 vendor
* 想象一下,我们的主文件,原来的bundle.js里面是不是包含了react,redux,react-router等等
这些代码??这些代码基本上不会改变的。但是,他们合并在bundle.js里面,每次项目发布,重新请求bundle.js的时候,相当于重新请求了
react等这些公共库。浪费了~
我们把react这些不会改变的公共库提取出来,用户缓存下来。从此以后,用户再也不用下载这些库了,无论是否发布项目。嘻嘻。
*/
entry:{
app: [
'react-hot-loader/patch',
path.join(__dirname, 'src/index.js')
],
vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']
},
/**
* 缓存
* 想象一下这个场景~
我们网站上线了,用户第一次访问首页,下载了home.js,第二次访问又下载了home.js~
这肯定不行呀,所以我们一般都会做一个缓存,用户下载一次home.js后,第二次就不下载了。
有一天,我们更新了home.js,但是用户不知道呀,用户还是使用本地旧的home.js。出问题了~
怎么解决?每次代码更新后,打包生成的名字不一样。比如第一次叫home.a.js,第二次叫home.b.js。
但是你可能发现了,网页打开报错了~因为你dist/index.html里面引用js名字还是bundle.js老名字啊,改成新的名字就可以啦。
HtmlWebpackPlugin
*/
output: {
path: path.join(__dirname, './dist'),
filename: '[name].[hash].js',
chunkFilename: '[name].[chunkhash].js'
},
/**
* 编译css
* css-loader使你能够使用类似@import 和
* url(...)的方法实现 require()的功能;
style-loader将所有的计算后的样式加入页面中;
二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。
*/
/**
* 编译图片
* options limit 8192意思是,
* 小于等于8K的图片会被转成base64编码,
* 直接插入HTML中,减少HTTP请求。
*/
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true'],
include: path.join(__dirname, 'src')
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192
}
}]
}
]
},
/**
* 简单来说,webpack-dev-server就是一个小型的静态文件服务器。使用它,可以为webpack打包生成的资源文件提供Web服务
* 2017.11.16补充:这里webpack-dev-server需要全局安装,要不后面用的时候要写相对路径。
* 需要再执行这个 npm install webpack-dev-server -g
* 执行命令:webpack-dev-server --config webpack.dev.config.js
* content-base: URL的根目录。如果不设定的话,默认指向项目根目录。
* 重要提示:webpack-dev-server编译后的文件,都存储在内存中,我们并不能看见的。你可以删除之前遗留的文件dist/bundle.js,
仍然能正常打开网站!
*/
/**
* 配置详解
* color(CLI only) console中打印彩色日志
historyApiFallback 任意的404响应都被替代为index.html。有什么用呢?你现在运行
npm start,然后打开浏览器,访问http://localhost:8080,然后点击Page1到链接http://localhost:8080/page1,
然后刷新页面试试。是不是发现刷新后404了。为什么?dist文件夹里面并没有page1.html,当然会404了,所以我们需要配置
historyApiFallback,让所有的404定位到index.html。
host 指定一个host,默认是localhost。如果你希望服务器外部可以访问,指定如下:host: "0.0.0.0"。比如你用手机通过IP访问。
hot 启用Webpack的模块热替换特性。关于热模块替换,我下一小节专门讲解一下。
port 配置要监听的端口。默认就是我们现在使用的8080端口。
proxy 代理。比如在 localhost:3000 上有后端服务的话,你可以这样启用代理:
*/
devServer: {
contentBase: path.join(__dirname, './dist'),
compress: true,
port: 9000,
historyApiFallback: true
},
/**
* webpack提供了一个别名配置,就是我们无论在哪个路径下,引用都可以这样
* import Home from 'pages/Home/Home';
* 修改之后需要重启
*/
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
pages: path.join(__dirname, 'src/pages'),
component: path.join(__dirname, 'src/component'),
router: path.join(__dirname, 'src/router'),
actions: path.join(__dirname, 'src/redux/actions'),
reducers: path.join(__dirname, 'src/redux/reducers'),
reduxPath: path.join(__dirname, 'src/redux')
}
},
/**
* 开始webpack调试,可以查看详细的错误信息,和断点调试
*/
devtool: 'inline-source-map',
/**
* HtmlWebpackPlugin 这个插件,每次会自动把js插入到你的模板index.html里面去。
*/
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(__dirname, 'src/index.html')
}),
]
};
发布配置说明
/**
* 开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,
* 我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的
* source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,
* 更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,
* 我们通常建议为每个环境编写彼此独立的 webpack 配置。
*/
const path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
/**
* 文件压缩
* webpack使用UglifyJSPlugin来压缩生成的文件
*/
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
/**
* 打包优化
* 你现在打开dist,是不是发现好多好多文件,每次打包后的文件在这里混合了?我们希望每次打包前自动清理下dist文件。
* 现在npm run build试试,是不是之前的都清空了。当然我们之前的api文件夹也被清空了,不过没关系哦~本来就是测试用的。
*/
const CleanWebpackPlugin = require('clean-webpack-plugin');
/**
* 抽取css
* 目前我们的css是直接打包进js里面的,我们希望能单独生成css文件。
我们使用extract-text-webpack-plugin来实现。
*/
const ExtractTextPlugin = require("extract-text-webpack-plugin");
/**
* 指定环境
* 许多 library 将通过与 process.env.NODE_ENV 环境变量关联,以决定 library 中应该引用哪些内容。
* 例如,当不处于生产环境中时,某些 library 为了使调试变得容易,
* 可能会添加额外的日志记录(log)和测试(test)。其实,
* 当使用 process.env.NODE_ENV === 'production' 时,一些 library 可能针对具体用户的环境进行代码优化,
* 从而删除或添加一些重要代码。我们可以使用 webpack 内置的 DefinePlugin 为所有的依赖定义这个变量:
* module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})
]
}
*/
/**
* 优化缓存
* 刚才我们把[name].[hash].js变成[name].[chunkhash].js后,npm run build后,
发现app.xxx.js和vendor.xxx.js不一样了哦。
但是现在又有一个问题了。
你随便修改代码一处,例如Home.js,随便改变个字,你发现home.xxx.js名字变化的同时,
vendor.xxx.js名字也变了。这不行啊。这和没拆分不是一样一样了吗?我们本意是vendor.xxx.js
名字永久不变,一直缓存在用户本地的。~
官方文档推荐了一个插件HashedModuleIdsPlugin
plugins: [
new webpack.HashedModuleIdsPlugin()
]
现在你打包,修改代码再试试,是不是名字不变啦?错了,现在打包,我发现名字还是变了,经过比对文档,我发现还要加一个runtime代码抽取,
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime'
})
加上这句话就好了~为什么呢?看下解释。
注意,引入顺序在这里很重要。CommonsChunkPlugin 的 'vendor' 实例,必须在 'runtime' 实例之前引入。
*/
/**
* public path
想象一个场景,我们的静态文件放在了单独的静态服务器上去了,那我们打包的时候,如何让静态文件的链接定位到静态服务器呢?
看文档Public Path
webpack.config.js output 中增加一个publicPath,我们当前用/,相对于当前路径,如果你要改成别的url,就改这里就好了。
output: {
publicPath : '/'
}
*/
module.exports = {
devtool: 'cheap-module-source-map',
entry:{
app: [
path.join(__dirname, 'src/index.js')
],
vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']
},
output: {
path: path.join(__dirname, './dist'),
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js',
publicPath : '/'
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
include: path.join(__dirname, 'src')
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192
}
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(__dirname, 'src/index.html')
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new UglifyJSPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new CleanWebpackPlugin(['dist']),
new ExtractTextPlugin({
filename: '[name].[contenthash:5].css',
allChunks: true
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime'
}),
],
/**
* webpack提供了一个别名配置,就是我们无论在哪个路径下,引用都可以这样
* import Home from 'pages/Home/Home';
* 修改之后需要重启
*/
resolve: {
alias: {
pages: path.join(__dirname, 'src/pages'),
component: path.join(__dirname, 'src/component'),
router: path.join(__dirname, 'src/router'),
actions: path.join(__dirname, 'src/redux/actions'),
reducers: path.join(__dirname, 'src/redux/reducers'),
reduxPath: path.join(__dirname, 'src/redux')
}
}
};