强缓存的优势很明显,无需向服务器发送请求,节省了大量的时间和带宽。但是有一个问题,缓存有效期内想更新资源怎么办?我在工程中还遇到另外一个问题,一个项目有四个环境,测试环境、开发环境、在线确认环境、在线环境,四个环境的域名相同,这样就会造成四个环境的缓存共用问题。比如先访问了测试环境,index.js被换成到浏览器中,再切换到在线环境,在线环境会请求index.js,此时浏览器就会使用本地缓存中测试环境的index.js,造成代码错乱。
如何使强缓存失效,是问题的关键。通常的解决方法是更新文件名,文件名不一样的话,浏览器就会重新请求资源。我们要保证新发布版本和不同环境中的文件名是不一样的。其中一种方法在文件名后加版本号:
index.js?version=1
index.css?version=1
webpack提供了很简单的方法可以配置缓存。
// webpack.config.js module.exports = { entry: "main.js", output: { path: "/build", filename: "main.[hash].js" } };
通过hash占位符,在每次生成打包文件时,都会通过文件内容生成唯一的hash,并添加到输出的文件名中。如果有多个入口文件,可以使用name占位符设置输出:
// webpack.config.js module.exports = { entry: { main:"main.js", sub:"sub.js" }, output: { path: "/dist", filename: "[name].[hash].js" } };
这时候有一个问题是,此时的hash是根据两个文件的内容来生成的,两个文件名使用的hash是一致的。如果main.js和sub.js只有一个改变,两个文件名都会改变,两个文件都会重新请求,造成资源浪费。webpack提供了chunkhash来代替hash在多入口情况下使用。chunkhash是根据每个入口文件单独生成的哈希值,避免上述情况。
webpack打包动态生成文件名,我们需要动态地把文件引用插入到html启动文件中。 html-webpack-plugin 可以帮我很好地解决这个问题。 html-webpack-plugin 可以动态地生成一个html文件,并在html文件中动态插入webpack打包生成的资源文件。
var HtmlWebpackPlugin = require('html-webpack-plugin'); var webpackConfig = { entry: 'main.js', output: { path: '/dist', publicPath: '/dist', filename: 'main.[hash].js' }, plugins: [new HtmlWebpackPlugin()] };
默认在 webpackConfig.output.path 路径下生成 index.html ,生成的html文件如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> </head> <body> <script src="https://www.jb51.net/main.2a6c1fee4b5b0d2c9285.js"></script> </body> </html>
通常html启动文件都有自定义的内容,所以 html-webpack-plugin 提供了模板功能,template字段设置模板的路径, html-webpack-plugin 以template为模板,动态添加webpack打包生成的资源路径。
var HtmlWebpackPlugin = require('html-webpack-plugin'); var webpackConfig = { entry: 'main.js', output: { path: '/dist', publicPath: '/dist', filename: 'main.[hash].js' }, plugins: [new HtmlWebpackPlugin( { template:'index.html' } )] };
原index.html内容(\index.html):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>stat-front</title> <link href="https://at.alicdn.com/t/font_ejl5slgdvtg74x6r.css" > </head> <body> <div> <router-view></router-view> </div> <!-- built files will be auto injected --> </body> </html>
生成的index.html内容(\dist\index.html):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>stat-front</title> <link href="https://at.alicdn.com/t/font_ejl5slgdvtg74x6r.css" > </head> <body> <div> <router-view></router-view> </div> <!-- built files will be auto injected --> <script src="https://www.jb51.net/main.2a6c1fee4b5b0d2c9285.js"></script> </body> </html>
最开始的时候静态的index.html在根目录下, webpack-dev-server 设置的启动路径就是根目录下的index.html,如果要启动生成的index.html,还需要设置 webpackConfig.output.publicPath :
var HtmlWebpackPlugin = require('html-webpack-plugin'); var webpackConfig = { entry: 'main.js', output: { path: '/dist', publicPath: 'https://www.jb51.net/', filename: 'main.[hash].js' }, plugins: [new HtmlWebpackPlugin( { template:'index.html' } )] };
这样webpack-dev-server在内存中生成的资源都存放在根目录下,生成的index.html会代替原index.html启动。
总结