正式开始吧,假设你已经懂什么是entry output loader plugin
webpack常见配置
// 入口文件 entry: { app: './src/js/index.js', }, // 输出文件 output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), publicPath: '/' //确保文件资源能够在 http://localhost:3000 下正确访问 }, // 开发者工具 source-map devtool: 'inline-source-map', // 创建开发者服务器 devServer: { contentBase: './dist', hot: true // 热更新 }, plugins: [ // 删除dist目录 new CleanWebpackPlugin(['dist']), // 重新穿件html文件 new HtmlWebpackPlugin({ title: 'Output Management' }), // 以便更容易查看要修补(patch)的依赖 new webpack.NamedModulesPlugin(), // 热更新模块 new webpack.HotModuleReplacementPlugin() ], // 环境 mode: "development", // loader配置 module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader' ] } ] }这里面我们重点关注 module和plugins属性,因为今天的重点是编写loader和plugin,需要配置这两个属性。
webpack 启动后,在读取配置的过程中会先执行 new MyPlugin(options) 初始化一个 MyPlugin获得其实例。在初始化 compiler 对象后,再调用 myPlugin.apply(compiler) 给插件实例传入 compiler 对象。插件实例在获取到 compiler 对象后,就可以通过 compiler.plugin(事件名称, 回调函数) 监听到 Webpack 广播出来的事件。 并且可以通过 compiler 对象去操作 webpack。
Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例;
Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler` 对象。Compiler 和 Compilation 的区别在于:Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译。事件流webpack 通过 Tapable来组织这条复杂的生产线。webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。webpack 的事件流机制应用了观察者模式,和 Node.js 中的 EventEmitter 非常相似。配置入口
entry: path.resolve(__dirname, '../src/main.js')}配置输出目录
output: { filename: 'js/[name].[hash:5].js', path: path.resolve(__dirname, '../dist'), },引入Vue脚手架里基本配置的loader ,后面的loader都是往rules数组里加就行了
module: { rules: [ { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [{ loader: 'url-loader', options: { limit: 10000, name: 'img/[name]-[hash:5].[ext]', } } ] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: 'fonts/[name]-[hash:5].[ext]', } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, use: [ { loader: 'url-loader', options: { limit: 4096, name: 'media/[name]-[hash:5].[ext]', } } ] } ] },有人会问 这么多我怎么看啊 别急 第一个url-loader是处理base64图片的,让低于limit大小的文件以base64形式使用,后面两个一样的套路,只是换了文件类型而已 ,不会的话,先复制过去跑一把?
配置识别.vue文件和tempalte模板 , yarn add vue vue-loader vue-template-compiler
加入loader { test:/\.vue$/, loader:"vue-loader" } 加入plugin const vueplugin = require('vue-loader/lib/plugin') 在webpack的plugin中 new vueplugin()即可入口指定babel-polifill ,vendor代码分割公共模块,打包后这些代码都会在一个公共模块
app: ['babel-polyfill', './src/index.js', './src/pages/home/index.js', './src/pages/home/categorys/index.jsx'], vendor: ['vuex', 'better-scroll', 'mint-ui', 'element-ui']指定 html文件为模板打包输出,自动引入打包后的js文件
const HtmlWebpackPlugin = require('html-webpack-plugin'); plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname,'../index.html'), filename: 'index.html' }), ]省掉.vue的后缀 ,直接配置在module.exports对象中,跟entry同级
resolve: { extensions: ['.js','.json','.vue'], }加入识别html文件的loader
{ test: /\.(html)$/, loader: 'html-loader' }开启多线程编译
const os = require('os') { loader: 'thread-loader', options: { workers: os.cpus().length } }加入babel-loader 加入 babel-loader 还有 解析JSX ES6语法的 babel preset
@babel/preset-env解析es6语法 @babel/plugin-syntax-dynamic-import解析vue的 import按需加载,附带code spliting功能 { loader: 'babel-loader', options: { //jsx语法 presets: ["@babel/preset-react", //tree shaking 按需加载babel-polifill ["@babel/preset-env", { "modules": false, "useBuiltIns": "false", "corejs": 2 }]], plugins: [ //支持import 懒加载 "@babel/plugin-syntax-dynamic-import", //andt-mobile按需加载 true是less,如果不用less style的值可以写'css' ["import", { libraryName: "antd-mobile", style: true }], //识别class组件 ["@babel/plugin-proposal-class-properties", { "loose": true }], ], cacheDirectory: true }, }在使用上面的babel配置后 我们躺着就可以用vueRouter的路由懒加载了
第二,在 Webpack 中,我们可以使用动态 import语法来定义代码分块点 (split point):
import('./Foo.vue') // 返回 Promise加入插件 热更新plugin和html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin') const webpack = require('webpack') new HtmlWebpackPlugin({ template: './src/index.html' }), new webpack.HotModuleReplacementPlugin(), devServer: { contentBase: '../build', open: true, port: 5000, hot: true },加入less-css识别的模块
{ test: /\.(less|css)$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' , options: { modules: false, //不建议开启css模块化,某些ui组件库可能会按需加载失败 localIdentName: '[local]--[hash:base64:5]' } }, { loader: 'less-loader', options: { javascriptEnabled: true } } ] },
html杀掉无效的代码
new HtmlWebpackPlugin({ template: './src/index.html', minify: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, useShortDoctype: true, removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, } }),加入图片压缩 性能优化很大
{ test: /\.(jpg|jpeg|bmp|svg|png|webp|gif)$/, use:[ {loader: 'url-loader', options: { limit: 8 * 1024, name: '[name].[hash:8].[ext]', outputPath:'/img' }}, { loader: 'img-loader', options: { plugins: [ require('imagemin-gifsicle')({ interlaced: false }), require('imagemin-mozjpeg')({ progressive: true, arithmetic: false }), require('imagemin-pngquant')({ floyd: 0.5, speed: 2 }), require('imagemin-svgo')({ plugins: [ { removeTitle: true }, { convertPathData: false } ] }) ] } } ] }加入file-loader 把一些文件打包输出到固定的目录下
{ exclude: /\.(js|json|less|css|jsx)$/, loader: 'file-loader', options: { outputPath: 'media/', name: '[name].[contenthash:8].[ext]' } }加入压缩css的插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') new OptimizeCssAssetsWebpackPlugin({ cssProcessPluginOptions:{ preset:['default',{discardComments: {removeAll:true} }] } }),加入code spliting代码分割 vue脚手架是同步异步分开割,我是直接一起割
optimization: { runtimeChunk:true, //设置为 true, 一个chunk打包后就是一个文件,一个chunk对应`一些js css 图片`等 splitChunks: { chunks: 'all' // 默认 entry 的 chunk 不会被拆分, 配置成 all, 就可以了拆分了,一个入口`JS`, //打包后就生成一个单独的文件 } }加入 WorkboxPlugin , PWA的插件
pwa这个技术其实要想真正用好,还是需要下点功夫,它有它的生命周期,以及它在浏览器中热更新带来的副作用等,需要认真研究。可以参考百度的lavas框架发展历史~ const WorkboxPlugin = require('workbox-webpack-plugin') new WorkboxPlugin.GenerateSW({ clientsClaim: true, //让浏览器立即servece worker被接管 skipWaiting: true, // 更新sw文件后,立即插队到最前面 importWorkboxFrom: 'local', include: [/\.js$/, /\.css$/, /\.html$/,/\.jpg/,/\.jpeg/,/\.svg/,/\.webp/,/\.png/], }),
单页面应用的优化核心 :
最重要的是路由懒加载 代码分割部分渲染在服务端完成 极大加快首屏渲染速度 VUE首选nuxt框架,也可以使用它的脚手架图片压缩和图片懒加载是对页面层次最大的优化之一后面继续书写next nuxt和pwa的使用~脚手架的搭建过程很多坑,但是却能大大提升你的技术天花板
福利,各种教程资源,应有尽有
《Java基础、入门、精通、架构师全套资源》