压缩js
使用自带的webpack.optimize.UglifyJsPlugin
const webpack = require('webpack');
module.exports = function(env) {
return {
entry: {
main: './index.js',
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
}),
]
}
}
分离css
1、安装extract-text-webpack-plugin插件
npm i --save-dev extract-text-webpack-plugin@beta
2、在webpack.config.js中使用这个插件
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = function () {
return {
entry: './index.js',
output: {
path: './dist',
filename: 'bundle.js'
},
module: {
rules: [{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
loader: 'css-loader'
})
}]
},
// devtool: 'source-map',
plugins: [
new ExtractTextPlugin({ filename: 'bundle.css', disable: false, allChunks: true })
]
}
}
提取公共文件
使用CommonsChunkPlugin的几种方式:
https://webpack.js.org/plugins/commons-chunk-plugin/#components/sidebar/sidebar.jsx
以下内容参考自:https://doc.webpack-china.org/guides/code-splitting-libraries/#-vendor-chunk
但是,如果我们改变应用的代码并且再次运行 webpack,可以看到 vendor 文件的 hash 改变了。即使我们把 vendor 和 main 的 bundle 分开了,也会发现 vendor bundle 会随着应用代码改变。
这意味着我们任然无法从浏览器缓存机制中受益,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。这里的问题在于,每次构建时,webpack 生成了一些 webpack runtime 代码,用来帮助 webpack完成其工作。当只有一个 bundle 的时候,runtime 代码驻留在其中。但是当生成多个 bundle的时候,运行时代码被提取到了公共模块中,在这里就是 vendor 文件。
为了防止这种情况,我们需要将运行时代码提取到一个单独的 manifest 文件中。尽管我们又创建了另一个 bundle,其开销也被我们在 vendor 文件的长期缓存中获得的好处所抵消。
// index.js
var moment = require('moment');
var path = require('path');
console.log(moment().format(), 11122334455);
console.log(path.resolve(__dirname, '/dist'));
console.log(path.join(__dirname, '/dist'));
// webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: ['moment', 'path'] // 提取moment,path模块到wendor文件
},
output: {
filename: '[name].js', // 原来是[chunkhash].[name].js
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
// name: 'vendor_modules',
// minChunks: function (module) {
// // 该配置假定你引入的 vendor 存在于 node_modules 目录中
// return module.context && module.context.indexOf('node_modules') !== -1;
// }
names: ['vendor', 'manifest']
}),
new HtmlWebpackPlugin({
template: './index.html' //使用当前目录(根目录)下的index.html
})
]
}
}
使用webpack打包后,dist目录命令有(xxxxx表示hash值)
index.html
xxxxx.main.js
xxxxx.manifest.js //webpack runtime 代码
xxxxx.vendor.js
修改index.js代码,再次打包后,只会生更新manifest.js和main.js。而最大的共同包vendor.js是不会变得。通过hash值可以看到。这样vendor.js就可以缓存到浏览器了。
提取公共文件+
https://doc.webpack-china.org/guides/caching/
为了最小化生成的文件大小,webpack 使用标识符而不是模块名称。在编译期间,生成标识符并映射到块文件名,然后放入一个名为 chunk manifest 的 JavaScript 对象中。
为了生成保存在构建中的标识符,webpack 提供了 NamedModulesPlugin
(推荐用于开发模式)和HashedModuleIdsPlugin
(推荐用于生产模式)这两个插件。
然后将 chunk manifest(与引导/运行时代码一起)放入 entry chunk,这对 webpack 打包的代码工作是至关重要的。
改变其他文件时mainfest.js改变
这个问题和以前一样:每当我们改变代码的任何部分时,即使它的内容的其余部分没有改变,都会更新我们的入口块以便包含新的映射(manifest)。 这反过来,将产生一个新的哈希值并且使长效缓存失效。
使用ChunkManifestWebpackPlugin
要解决这个问题,我们应该使用 ChunkManifestWebpackPlugin,它会将 manifest 提取到一个单独的 JSON 文件中。 这将用一个 webpack runtime 的变量替换掉chunk manifest。 但我们可以做得更好;我们可以使用 CommonsChunkPlugin 将运行时提取到一个单独的入口起点(entry)中去。这里是一个更新后的 webpack.config.js,将生成我们的构建目录中的 manifest 和 runtime 文件:
// webpack.config.js
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin"); module.exports = {
/*...*/
plugins: [
/*...*/
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "manifest"], // vendor libs + extracted manifest
minChunks: Infinity,
}),
/*...*/
new ChunkManifestPlugin({ filename: "chunk-manifest.json", manifestVariable: "webpackManifest" })
]
};
因为我们从入口块(entry chunk)中移除了 manifest,所以我们现在有责任为 webpack 提供它。上面示例中的 manifestVariable 选项是全局变量的名称,webpack 将利用它查找 manifest JSON 对象。这个变量应该在我们引入 bundle 到 HTML 之前就定义好。这是通过在 HTML 中内联 JSON 的内容来实现的。我们的 HTML 头部应该像这样:
<!-- 这里我不明白webpackManifest的作用 -->
<html>
<head>
<script>
//<![CDATA[ window.webpackManifest = {"0":"main.5f020f80c23aa50ebedf.js","1":"vendor.81adc64d405c8b218485.js"} //]]>
</script>
</head>
<body>
</body>
</html>
在结束时,文件的哈希值应该基于文件的内容。对此,我们可以使用 webpack-chunk-hash 或者 webpack-md5-hash。
所以最终的 webpack.config.js 看起来像这样:
var path = require("path");var webpack = require("webpack");
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");
var WebpackChunkHash = require("webpack-chunk-hash");
module.exports = {
entry: {
vendor: "./src/vendor.js", // vendor reference file(s)
main: "./src/index.js" // application code
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].[chunkhash].js",
chunkFilename: "[name].[chunkhash].js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "manifest"], // vendor libs + extracted manifest
minChunks: Infinity,
}),
new webpack.HashedModuleIdsPlugin(),
new WebpackChunkHash(),
new ChunkManifestPlugin({
filename: "chunk-manifest.json",
manifestVariable: "webpackManifest"
})
]};
使用webpack-dev-server
关于API:https://doc.webpack-china.org/configuration/dev-server/
// package.json
// 其中scripts这样设置
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --devtool eval-source-map --progress --colors"
},
- 关于devtool:https://doc.webpack-china.org/configuration/devtool/
- –progress 打印打包日志
- –colors带颜色的日志
// webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: ['moment', 'path']
},
output: {
// filename: '[chunkhash].[name].js',
filename: '[name].js',
publicPath: "/assets/",
path: path.resolve(__dirname, 'build')
},
devServer: {
inline: true,
port: 8099,
contentBase: path.join(__dirname, 'build')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest']
}),
new HtmlWebpackPlugin({
template: './index.html'
}),
// etc.
]
}
}
使用npm run dev的时候,可以看到输出有以下:
不会实际生成文件夹,这一部分,推荐看这里:https://github.com/liangklfangl/webpack-dev-server/commit/9b9b86beffedee9c15c7ba3a807b30eb78d477e9
> webpack-dev-server --devtool eval-source-map --progress --colors
10% building modules 2/2 modules 0 active
Project is running at http://localhost:8099/
webpack output is served from /assets/
Content not from webpack is served from C:\Users\real\...\build
10%Hash: d968bc9b6ab05170f44f
Version: webpack 2.2.1
-
在 dev-server 的两种不同模式之间切换。默认情况下,应用程序启用内联模式(inline
mode)。这意味着一段处理实时重载的脚本被插入到你的包(bundle)中,并且构建消息将会出现在浏览器控制台。 也可以使用 iframe模式,它在通知栏下面使用<iframe>
标签,包含了关于构建的消息。
切换到 iframe 模式:inline:false
当使用模块热替换时,建议使用内联模式(inline mode)。 output.path:指定编译目录而已(/build/),不能用于html中的js引用。
output.publicPath/devServer.publicPath:publicPath:虚拟目录,自动指向path编译目录(/assets/ => /build/)。html中引用js文件时,必须引用此虚拟路径(但实际上引用的是内存中的文件,既不是/build/也不是/assets/)。
devServer.contentBase:指明应用根目录,与上面两个配置项毫无关联。
所以在我打开localhost:8099的时候,如果设置了contentBase,那么就会跳到contentBase指明的目录,这里是:C:\Users\real\...\build
,这个目录是不会自动生成的,如果手动建立了这个目录,就会去找到这个目录下的index.html文件。否则,不能找到。
实际上可以访问的是:localhost:8099/assets/index.html,访问这个文件,会看到我们写的index.html,其中index.html自动引用了生成的main.js、vendor.js、manifest.js。并且当我们修改js文件的时候,页面会自动刷新。
热更新
webpack中文网的一个例子:实测可用。
https://doc.webpack-china.org/guides/hmr-react/
我的在这里:http://blog.csdn.net/real_bird/article/details/62927644
require.ensure
参考自:
http://blog.csdn.net/zhbhun/article/details/46826129
https://doc.webpack-china.org/guides/code-splitting-require/
说明: require.ensure在需要的时候才下载依赖的模块,当参数指定的模块都下载下来了(下载下来的模块还没执行),便执行参数指定的回调函数。require.ensure会创建一个chunk,且可以指定该chunk的名称,如果这个chunk名已经存在了,则将本次依赖的模块合并到已经存在的chunk中,最后这个chunk在webpack构建的时候会单独生成一个文件。
考虑下面的文件结构:
.
├── dist
├── js
│ ├── a.js
│ ├── b.js
│ ├── c.js
│ └── entry.js
└── webpack.config.js
entry.js
require('./a');
require.ensure(['./b'], function(require){
require('./c');
console.log('done!');
});
a.js
console.log('***** I AM a *****');
b.js
console.log('***** I AM b *****');
c.js
console.log('***** I AM c *****');
webpack.config.js
var path = require('path');
module.exports = function(env) {
return {
entry: './js/entry.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
// publicPath: 'https://cdn.example.com/assets/',
// tell webpack where to load the on-demand bundles.
publicPath: __dirname + '/dist/',
pathinfo: true,
// show comments in bundles, just to beautify the output of this example.
// should not be used for production.
}
}
}
通过执行这个项目的 webpack 构建,我们发现 webpack 创建了 2 个新的 bundle,bundle.js 和 0.bundle.js。
entry.js 和 a.js 被打包进 bundle.js。b.js和c.js被打包进0.bundle.js。0.bundle.js是按需加载的(通过output.publicPath,这里我修改了,以便能正确加载到)。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="dist/bundle.js" charset="utf-8"></script>
</head>
<body>
</body>
</html>
打开这个文件后可以看到,它自动加载了0.bundle.js。
而在控制台输出的是:
***** I AM a *****
***** I AM c *****
done!
这就说明了虽然require.ensure中虽然依赖了b.js,但是没有require('./b');
,所以就没有打印出来。模块虽然下载了,但必须手动require才会执行。就算没有使用require('./c');
,0.bundle.js还是会被加载的。注意到,这里是async
。