Webpack抽离第三方类库以及common解决方案
前端构建场景有两种,一种是单页面构建,另一种是多入口构建多页面应用程序(我视野比较小,目前就知道这两种),下面我们针对这两种场景总结了几种抽离第三方类库以及公共文件的解决方案。
如果有哪些地方优化不周到,请指点一二,另外求关注求星星,么么哒
单页面构建:
常规配置
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = {
mode: "development",
entry: {
app: './app.js'
},
output: {
path: path.resolve(__dirname, './build/'),
filename: "bundle-[chunkhash:8].js"
},
devtool: "source-map",
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
],
exclude: /node_modules/
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // translates CSS into CommonJS
'less-loader', // compiles Less to CSS
],
exclude: /node_modules/
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [{
loader: 'file-loader',
options: {
limit: 1024,
}
}],
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[chunkhash:8].css",
chunkFilename: "[id].[chunkhash:8].css"
}),
new HtmlWebpackPlugin({
title: 'webpack',
template: './index.html',
chunks: ['app']
}),
new CleanWebpackPlugin()
],
}
在脚本种我们常规写法是这样的
require('./main-less.less');
require('./main-css.css');
const ReactDOM = require('react-dom');
const React = require('react');
import Main from './main.js';
// /**
// * 引入 scope hisiting test
// */
// import B from './ScopeHisitingTest/b';
ReactDOM.render(
<Main />,
document.getElementById('app')
)
我们看下构建输出结果
现在我们看到这个应该思考三个问题
1.脚本部分,难道每个页面都要写一边import React&ReactDOM 吗
2.构建体积能不能再缩小一点
3.构建速度能不能在快一点
以上三个问题都会在开发过程中耽误开发效率,我们开始处理这三个问题
方案1
html全局引用第三方类库,比如React,因为React源码中将React挂在到了window上,这么做解决了什么呢,脚本里面我们不用在每一个页面中引用第三方类库了,我们看下代码
<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
</head> <body>
<div id='app'></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</body> </html>
好了解决了脚本部分不用每个页面都需要import一次了
构建体积怎么减小呢
这里我们可以借助webpack插件,下面我们上代码
externals: {
'react': 'react',
'react-dom': 'react-dom'
},
我们将两个第三方类库打包的时候不依赖进去,通过这种方式告诉webpack,在构建过程中引用react以从内存中引用的方式,我们看下打包效果
可以明显的看到,采用这种用法之后会有一个问题就是,我们在目标脚本文件里面就不能在引用第三方类库了,不然打包进去,external会以具体文件形式引用第三方类库,从而导致找不到而报错,直接用就好了,我们毕竟要解决的就是这个问题嘛。
以上就是第一种解决方案,当然这并不是根本的解决方案,只是个大体思路,我们可以再改进一下。
第二种
通过组织模块的形式包装第三方类库,从而打到第三方类库挂载到全局的效果
首先创建一个用来专门打包第三方的webpack
const path = require('path');
module.exports = {
mode: 'development',
entry: {
app: './vendorentry.js',
},
output: {
path: path.resolve(__dirname, './vendor/'),
filename: "dll.js",
library:'util',
libraryTarget: 'window'
},
}
这里就不做任何优化了,毕竟打包第三方的,我们也不需要在提取什么文件了。这里注意的是通过组织模块打包方式libraryTarget,以及暴露给全局的名称util。
创建一个入口文件,来引用第三方类库的集合
import $ from "jquery";
import React from "react";
import ReactDOM from "react-dom"; window.React = React;
window.ReactDOM = ReactDOM;
window.$ = $; export { $, React, ReactDOM };
输出结果
所有的第三方都在util下,其实我们只是规定了在业务逻辑的webpack中要以某种形式去加载,而不是打到最终包里,这就是我们的核心目的。
html中可以动态替换目标dll,配置如下
new HtmlWebpackPlugin({
templateContent: () => {
let template = path.resolve(__dirname, './index.html');
return read(template)
.toString()
.replace('$dll$', '../vendor/dll.js');
},
title: 'index',
template: './index.html',
filename: 'index.html',
chunks: ['app'],
hash: true
}),
业务逻辑webpack配置
externals: {
'react': 'window.util.React',
'react-dom': 'window.util.ReactDOM',
'jQuery': 'window.util.jquery',
'$': 'window.util.jquery'
}
第三种
第三种方式采用将第三方类库打包到指定的dll中,通过webpack构建应用时引用
涉及两个Plugin,分别是DllReferencePlugin,DllPlugin
首先创建一个专门针对dll的webpack配置文件
const webpack = require('webpack');
const path = require('path'); module.exports = {
entry: {
react: [
'react',
'react-dom'
]
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, './distDll/dll/'),
library: '[name]_dll_[hash]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]_dll_[hash]',
context: __dirname,
path: path.join(__dirname, 'distDll/dll', '[name].manifest.json')
})
]
}
然后执行这个webpack,生成dll以及描述模块运行依赖的manifest.json,我们应用的webpack需要引用这个dll
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./distDll/dll/react.manifest.json')
}),
到这里就结束了吗,并不是,我们执行下webpack会发现,React找不到了,我们首先考虑到什么,难道是external的问题吗,你会发现跟它一点关系没有,难道我们每次写还要导入第三方类库吗,解决方案
ProvidePlugin
new webpack.ProvidePlugin({
'React': 'react',
'ReactDOM': 'react-dom'
})
这样就解决了这个问题,我们看下构建效果
同样也达到了我们的目的。
多入口
多入口采用optimization分离,其实与多页面分离第三方与common部分的用法是一样的,我们就跟多页面一起具体了。
多页面解决方案
基本配置
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {
mode: 'development',
entry: {
app1: './app1.js',
app2: './app2.js'
},
output: {
path: path.resolve(__dirname, './build/'),
filename: "[name]-[chunkhash].js"
},
devtool: "source-map",
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
},
'less-loader', ],
exclude: /node_modules/
},
{
test: /\.js$/,
use: [
'cache-loader',
{
loader: 'babel-loader',
}
],
exclude: /node_modules/
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash:5].css',
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'index1',
template: './index1.html',
filename: 'index1.html',
chunks: ['app1', 'common'],
// hash: true
}),
new HtmlWebpackPlugin({
title: 'index2',
template: './index2.html',
filename: 'index2.html',
chunks: ['app2', 'common'],
// hash: true
}),
new webpack.HashedModuleIdsPlugin(),
], }
打包效果
问题很明显,速度慢,体积过大,这里还有个问题就是,app1的与app2引用共同的文件导致的体积过大,也就是我们要解决的如何提取common部分的问题,这里我们就不讨论脚本import 第三方的问题了,上面有解决方案了。
提取common部分
optimization: {
runtimeChunk: {
"name": "manifest"
},
splitChunks: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
common: {
test: /\.(s*)js$/,
chunks: 'all',
minChunks: 2,
minSize: 0,
name: 'common',
enforce: true,
priority: -11
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -10,
chunks: 'all',
reuseExistingChunk: true,
enforce: true
},
style: {
name: 'style',
test: /\.less$/,
chunks: 'all',
enforce: true
}
}
},
runtimeChunk:{
name:'manifest'
}
},
这里我们要做的是,提供commonjs,合并css(提取common部分也是可以的,毕竟页面也不可能用全部的css,做法与提取commonjs是一样的,配置minChunks最小为2就可以了),提供第三方类库。
我们看下打包效果
速度提升了,同时生成了common文件以及提三方文件集合verndors文件,嗯,目前解决了我们要解决的问题,上面单页面场景同样适用,浏览器缓存这个一般不会变得vendors,也达到了提升效率问题,
但是有没有想过一个问题,就是每一次webpack构建过程,是不是都要打一次这个包呢,浪费时间了吧,于是我们采用什么方式呢,没错~采用DllPlugin与DllReferencePlugin来提取一次第三方,
剩下common部分每一次构建都去重新打一次。
代码同样引用dll
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./distDll/dll/react.manifest.json')
})
构建效果
效果就是大幅度提升构建速度。
最终配置文件
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {
mode: 'development',
entry: {
app1: './app1.js',
app2: './app2.js'
},
output: {
path: path.resolve(__dirname, './build/'),
filename: "[name]-[chunkhash].js"
},
devtool: "source-map",
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
// options: {
// sourceMap: true,
// modules: true,
// localIdentName: '[name]---[local]---[hash:base64:5]'
// }
},
'less-loader', ],
exclude: /node_modules/
},
{
test: /\.js$/,
use: [
'cache-loader',
{
loader: 'babel-loader',
options: {
// cacheDirectory: path.join(__dirname,'./build/', 'babel_cache')
// happyPackMode: true,
// transpileOnly: true
}
}
],
exclude: /node_modules/
}
]
},
optimization: {
runtimeChunk: {
"name": "manifest"
},
splitChunks: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
common: {
test: /\.(s*)js$/,
chunks: 'all',
minChunks: 2,
minSize: 0,
name: 'common',
enforce: true,
priority: -11
},
// vendors: {
// test: /[\\/]node_modules[\\/]/,
// name: "vendors",
// priority: -10,
// chunks: 'all',
// reuseExistingChunk: true,
// enforce: true
// },
style: {
name: 'style',
test: /\.less$/,
chunks: 'all',
enforce: true
}
}
},
runtimeChunk:{
name:'manifest'
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash:5].css',
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'index1',
template: './index1.html',
filename: 'index1.html',
chunks: ['app1', 'common'],
// hash: true
}),
new HtmlWebpackPlugin({
title: 'index2',
template: './index2.html',
filename: 'index2.html',
chunks: ['app2', 'common'],
// hash: true
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./distDll/dll/react.manifest.json')
})
], }
以上就是针对webpack构建优化全部总结,涉及第三方抽取,common抽取等问题。
求个关注~谢谢,么么哒~
Webpack抽离第三方类库以及common解决方案的更多相关文章
- webpack配置:打包第三方类库、第三方类库抽离、watch自动打包、集中拷贝静态资源
一.打包第三方类库 下面说2种方法: 第一种: 1.引入jQuery,首先安装: npm install --save-dev jquery 2.安装好后,在index.js中引入,用jquery语法 ...
- webpack快速入门——实战技巧:优雅打包第三方类库
下面说两种方法: 一. 1.引入jQuery,首先安装: cnpm install --save jquery 2.安装好后,在我们的entry.js中引入: import $ from 'jquer ...
- @ResponseBody 返回json字符串的核心类是org.springframework.http.converter.json.MappingJacksonHttpMessageConverter,它使用了Jackson 这个开源的第三方类库。主要是以下两个jar包:jackson-core-asl-1.6.4.jar;jackson-mapper-asl-1.6.4.jar
@ResponseBody 返回json字符串的核心类是org.springframework.http.converter.json.MappingJacksonHttpMessageConvert ...
- iOS 如何在一个已经存在多个project的workspace中引入cocoapods管理第三方类库
一种新的第三方库管理工具:Carthage 如何使用Carthage管理iOS依赖库 Podfile Syntax Reference v1.1.0.rc.3 https://guides.cocoa ...
- 使用cocoapods管理第三方类库
前言 在iOS项目中使用第三方类库可以说是非常常见的事,但是要正确地配置他们有时候是非常繁琐的事情,幸运的是CocoaPods是一个很好的解决方案. 什么是CocoaPods CocoaPods是OS ...
- iOS开发 使用Cocoapods管理第三方类库
每次上github看到一些优秀的代码,总能看到Podfile,也了解是个管理第三方类库的,今天抽时间学习了一下,挺简单的! 作用: 太多 还是复制一下把!!! CocoaPods是什么? ...
- Laravel 引入第三方类库及自定义函数
1.新建一个目录放第三方类库 2.找到composer.json文件打开,在里面autoload 下classmap下面加入类库路径 3根目录下运行composer dumpautoload 4.使用 ...
- Android Studio导入第三方类库的方法
Android Studio导入第三方类库的方法 本人也刚刚开始尝试做android app的开发,听说android studio是Google支持的android 应用开发工具,所以想应该肯定比E ...
- iOS 常用第三方类库、完整APP示例
一.第三方类库 1:基于响应式编程思想的oc地址:https://github.com/ReactiveCocoa/ReactiveCocoa2:hud提示框地址:https://github.com ...
随机推荐
- ERROR: Error in Log_event::read_log_event(): 'Found invalid event in binary log', data_len: 31, event_type: 35报错处理
centos7系统MySQL5.7在用mysqlbinlog命令查询binlog日志时刚开始查询即自动终止查询,查了一下该日志有300M,于是仔细看发现有报错,见下图: 在网上查找经验贴http:// ...
- ES介绍与实践
一.ES介绍 1.基础概念介绍 1. 索引:Elasticsearch中的“索引”有点像关系数据库中的数据库. 它是存储/索引数据的地方: 2.分片 shard “分片”是Lucene的一个索引. 它 ...
- 查漏补缺:QT入门
1.什么世QT Qt是一个跨平台的C++图形用户界面应用程序框架,为应用程序开发者提供建立艺术级图形界面所需的所有功能.它是完全面向对象的,容易扩展,并且允许真正的组建编程. 2.支持平台 Windo ...
- Redis(1)——5种基本数据结构
一.Redis 简介 "Redis is an open source (BSD licensed), in-memory data structure store, used as a d ...
- C++扬帆远航——1
问题及代码: /* * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:test.cpp * 作者:常轩 * 完成日期:2 ...
- sql服务器第5级事务日志管理的阶梯:完全恢复模式下的日志管理
sql服务器第5级事务日志管理的阶梯:完全恢复模式下的日志管理 原文链接http://www.sqlservercentral.com/articles/Stairway+Series/73785/ ...
- 时间序列数据库(TSDB)初识与选择(InfluxDB、OpenTSDB、Druid、Elasticsearch对比)
背景 这两年互联网行业掀着一股新风,总是听着各种高大上的新名词.大数据.人工智能.物联网.机器学习.商业智能.智能预警啊等等. 以前的系统,做数据可视化,信息管理,流程控制.现在业务已经不仅仅满足于这 ...
- CSS的常用单位 %和 vw vh 和 box-sizing:border-box; 和flex简介
一.% 理解: %号是CSS中的常用单位,它是相对于父容器而言的.如:一个父容器的宽是100px,给它的子元素一个10%,那么子元素的宽就是100px的10% 10px. 效果图: (利用%设置了li ...
- .NET微服务从0到1:服务注册与发现(Consul)
目录 Consul搭建 基于Docker搭建Consul 基于Windows搭建Consul ServiceA集成Consul做服务注册 Ocelot集成Consul做服务发现 更多参考 Consul ...
- Spring Boot 2.x基础教程:使用MyBatis的XML配置方式
上一篇我们介绍了如何在Spring Boot中整合我们国人最常用的MyBatis来实现对关系型数据库的访问.但是上一篇中使用了注解方式来实现,而对于很多MyBatis老用户还是习惯于XML的开发方式, ...