webpack 指南
entry
配置入口文件 webpack4中有默认,但也是可扩展的配置
- 单入口写法
const config = { entry: './file.js' }; 相当于 const config = { entry: { main: './file.js' } }复制代码
- 数组
会创建多个主入口
- 对象写法 可重用并且可以与其他配置组合使用。
output
只指定一个输出配置。 值为一个对象包括:
- filename:输出文件的文件名
- path: 目标输出目录的绝对路径
//单入口时 const config = { filename: './bundle.js', path: '/dist/js' //绝对路径 }//多入口const config = { filename: '[name].js', path:path.resolve(__dirname , 'dist') }复制代码
mode
- production 提供优化,代码压缩,不支持watching,process.env.NODE_ENV 的值默认production
- development 优化构建速度和开发体验 process.env.NODE_ENV 的值默认development 支持注释和提示
- none 禁用一切优化
loader
loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块 (webpack 自身只理解 JavaScript)
- 导出为函数的javascript模块
- 链式调用 把上一个loader产生的结果或资源文件放进去
加载相应的资源文件 loader webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader
{ test:/\.css$/,use:['style-loader','css-loader']}复制代码
plugin
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。
- HtmlWebpackPlugin 生成html文件,并自动引入打包生成的js文件
- CleanWebpackPlugin在每次构建前清理 /dist 文件夹
- NamedModulesPlugin
- HotModuleReplacementPlugin/WebpackHotMiddleware
- optimization.splitChunks
optimization:{ splitChunks:{ cacheGroups: { commons: { name: "commons", chunks: "initial", minChunks: 2 } } } }复制代码
- DefinePlugin 定义全局常量
new webpack.DefinePlugin({ PRODUCTION: JSON.stringify(true), VERSION: JSON.stringify("5fa3b9"), BROWSER_SUPPORTS_HTML5: true, TWO: "1+1", "typeof window": JSON.stringify("object") })复制代码
-----------分割线————————
开发
- 开发模式下使用source-map,可以准确定位错误的位置
- 观察模式 如果其中一个文件被更新,代码将被重新编译,不必手动运行整个构建。 package.json watch: 'webpack --watch' npm run watch
- webpack-dev-server 提供简单的web服务器 并实时加载
- webpack-dev-middleware (server.js)
生产环境构建
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。
- 公共配置
- 开发环境配置 webpack-merge
- 生产环境配置 webpack-merge
代码分离
- 多入口 打包多个js (如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。 这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。)
- 防止重复 4之前CommonsChunkPlugin 4之后 optimization.splitChunks
- 动态导入 不在页面一开始就import 需要用到的地方在import (import() 会返回一个 promise,因此它可以和 async 函数一起使用)
- bundle analysis A. webpack-chart: webpack 数据交互饼图。 B. webpack-visualizer: 可视化并分析你的 bundle,检查哪些模块占用空间,哪些可能是重复使用的。 C. webpack-bundle-analyzer: 一款分析 bundle 内容的插件及 CLI 工具,以便捷的、交互式、可缩放的树状图形式展现给用户。
懒加载
懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。
- React https://reacttraining.com/react-router/web/guides/code-splitting
- Vue https://alexjoverm.github.io/2017/07/16/Lazy-load-in-Vue-using-Webpack-s-code-splitting/
缓存
- 输出文件名称使用 [name].[chunkhash].js 重新编译时,文件名可能会变也可能不会变 可以使用插件:第一个插件是 NamedModulesPlugin,将使用模块的路径,而不是数字标识符。虽然此插件有助于在开发过程中输出结果的可读性,然而执行时间会长一些。第二个选择是使用 HashedModuleIdsPlugin,推荐用于生产环境构建
渐进式网络应用程序
PWA 在离线(offline)时应用程序能够继续运行功能。这是通过使用名为 Service Workers 的网络技术来实现的。
- 建议服务器,搭建所需的离线环境 npm install http-server
- 添加workbox 打包时会生成两个额外文件 service-worker.js,precache....js
new WorkboxPlugin.GenerateSW({ //这些选项帮助 ServiceWorkers 快速启用 //不允许遗留任何“旧的” ServiceWorkers clientsClaim: true, skipWaiting: true })复制代码
- 注册 Service Worker
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js').then(registration => { console.log('SW registered: ', registration); }).catch(registrationError => { console.log('SW registration failed: ', registrationError); }); }); }复制代码
- 打包后 重新运行 如果成功 关闭服务器 应用程序会继续运行
typescript
- npm install typescript ts-loader --save
- 新建tsconfig.json文件
{ "complierOptions": { "outDir":'./dist/', "sourceMap": true,//启用source map "noImplicitAny": true, "module": 'es6', "target": 'es5', //编译到es5 "jsx": "react", //支持jsx "allowJs": true, }}复制代码
-
webpack.config.js 使用ts-loader编译
-
使用其他资源 (非代码资源) 需要告诉 TypeScript 如何兼容这些导入类型 新建custom.d.ts文件
declare module "*.svg" { const content: any; export default content;}//通过指定任何以 .svg 结尾的导入,并将模块的 content 定义为 any,将 SVG 声明一个新的模块//可以通过将类型定义为字符串,来更加显式地将它声明为一个 url复制代码
tree shaking
package中设置"sideEffects": false,将不会打包没有用到的导出部分,可以安全地删除文件中未使用的部分。
shimming
一些第三方的库可能会引用一些全局依赖。这些库可能创建一些需要被导出的全局变量。这些“不符合规范的模块”就是 shimming 发挥作用的地方。 当你希望 polyfill 浏览器功能以支持更多用户时。在这种情况下,你可能只想要将这些 polyfills 提供给到需要修补(patch)的浏览器(也就是实现按需加载)。
- shimming 全局变量 ProvidePlugin
- 当模块运行在 CommonJS 环境下此时的 this 指向的是 module.exports。可以通过使用 imports-loader 覆写 this
module: { rules: [ { test: require.resolve('index.js'), use: 'imports-loader?this=>window' } ]},复制代码
- 全局exports exports-loader,将一个全局变量作为一个普通的模块来导出。
{ test: require.resolve('globals.js'), use: 'exports-loader?file,parse=helpers.parse'}//使用//import { file, parse } from './globals.js';复制代码
- 加载polyfills
在单独文件中引入 babel-polyfills whatwg-fetch 打包成单独js文件 依赖于那些需要支持的技术以及浏览器,来确定是否需要引入这些 polyfills
var modernBrowser = ( 'fetch' in window && 'assign' in Object ); if ( !modernBrowser ) { var scriptElement = document.createElement('script'); scriptElement.async = false; scriptElement.src = '/polyfills.bundle.js'; document.head.appendChild(scriptElement); }复制代码
构建性能
- 将loaders应用于最少的必要模块,使用include字段
- 尽量减少使用不同的工具
- 尽量减少 resolve.modules, resolve.extensions, resolve.mainFiles, resolve.descriptionFiles 中类目的数量,他们会增加文件系统调用的次数。
- 使用 DllPlugin 将更改不频繁的代码进行单独编译。
- 减少编译的整体大小
- 使用更小的库
- optimization.splitChunks
- 移除不使用的代码
- 只编译开发中的代码