wepack is a module bundle:模块打包工具。javascript
模块:不限于js文件,CSS文件,图片等等。css
ES Module CommonJs AMD CMDhtml
安装方式:java
全局 npm install webpack webpack-cli -g
node
项目中安装 (推荐)react
npm install webpack webpack-cli --save-dev
webpack
npm install webpack webpack-cli -D
git
解决:npx webpack -ves6
npx命令会去当前项目目录的node-modules寻找webpack
github
初始化 npm init -y
(自动生成默认配置项)
npm info webpack
(查看包的版本号)
npm install
下载全部依赖包
注:不建议安装在全局。不一样两个项目,若是webpack版本号不同,一个3,一个4,其中一个运行不起来
npx webpack index.js
npx webpack --config mywebpackconfig.js
const path = require('path')
module.exports = {
mode: 'production(压缩代码)/development(不压缩代码)' //默认production
entry: {
main: './src/index.js'
},
output: {
filename: '[name].js', //占位符
path: path.resolve(__dirname, 'bundle'), //绝对路径
publicPath: "http://baidu.com" //添加前缀地址
}
}
复制代码
process.cwd()
:是当前执行node命令时候的文件夹地址 ——工做目录,保证了文件在不一样的目录下执行时,路径始终不变__dirname
:是被执行的js 文件的地址 ——文件所在目录{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle": "webpack" //在scripts中直接运行webpack,默认如今当前目录中找,至关于 npx webpack,
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.39.0",
"webpack-cli": "^3.3.6"
}
}
复制代码
Hash: 714f926a0d1129251086
Version: webpack 4.39.0
Time: 683ms
Built at: 2019-08-02 15:52:43
Asset Size Chunks /*打包的文件的id值*/ Chunk Names、/*打包的文件的名字,配置文件中entry配置的文件名 */
main.js 1.17 KiB 0 [emitted] main
Entrypoint main = main.js
[0] ./index.js + 2 modules 480 bytes {0} [built]
| ./index.js 100 bytes [built]
| ./Header.js 190 bytes [built]
| ./Footer.js 190 bytes [built]
复制代码
npm install moduleName
命令
npm install -g moduleName
命令
npm install -save moduleName
命令
npm install -save-dev moduleName
命令
总结 devDependencies 节点下的模块是咱们在开发时须要用的,好比项目中使用的 gulp ,压缩css、js的模块。这些模块在咱们的项目部署后是不须要的,因此咱们可使用 -save-dev 的形式安装。像 express 这些模块是项目运行必备的,应该安装在 dependencies 节点下,因此咱们应该使用 -save 的形式安装。
webpack默认打包js文件,不认识CSS文件或者图片文件等等。
loader:打包的方案。
file-loader
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
//placeholder
outputPath: 'images/',
name: '[name]_[hash].[ext]'
}
}
}
]
}
复制代码
url-loader
Name | 类型 | 默认 | 描述 |
---|---|---|---|
limit |
number |
undefined |
限制文件大小 |
mimetype |
string |
extanme |
指定文件的mimetype (不然从文件拓展名推断) |
fallback |
string |
file-loader |
loader 文件大于限制时,指定loader 打包文件 |
将图片以base64的形式打包在js文件里。
limit
:限制图片大小,若是小于这个值,打包成base64,大于这个值,和file-loader同样。
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
//placeholder
outputPath: 'images/',
name: '[name]_[hash].[ext]',
limit: 2048 //限制小于2048(2kb)打包成base64的形式。不然以图片的形式打包到 bundle目录下。 好处是:能够减小一些小图片的http请求数目,提高网 页加载速度
}
}
}
]
}
复制代码
style-loader:将样式以style标签的形式,写在html文件的head中。
css-loader:将样式文件分析合并,打包。
sass-loader:将scss文件翻译成css。
postcss-loader:能够自动加厂商前缀 -webkit
新建postcss.conifg.js
npm i -D autoprefixer
module.exports = {
plugins : [
require('autoprefixer')({
overrideBrowserslist : ['last 2 versions'] //必须设置支持的浏览器才会自动添加添 加浏览器兼容
})
]
};
复制代码
loader的使用顺序是从下到上:
{
test: /\.(css|less|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader'
]
}
复制代码
{
test: /\.(css|less|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2 //目录文件中经过import引入的文件,可能不会走sass-loader和 postcss-loader ,这个配置项为了让import引入的css文件,再过2个loader。
}
},
'sass-loader',
'postcss-loader'
]
}
复制代码
CSS Module (CSS模块化)
{
test: /\.(css|less|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true //CSS Module
}
},
'sass-loader',
'postcss-loader'
]
}
复制代码
import style from './style.scss';
img.classList.add(style.a); //不一样文件添加不一样的样式
复制代码
webpack打包字体文件
file-loader
plugin
能够在webpack
运行到某一个时刻的时候,帮你作一些事情。(相似生命周期函数)
html-webpack-plugin
会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。
const htmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new htmlWebpackPlugin({
template: "./src/index.html" //默认不会生成 <div id="dom2"></div> 须要模板
})
],
复制代码
clean-webpack-plugin
会在打包以前,删除以前打包过的文件。
const htmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
plugins: [
new htmlWebpackPlugin({
template: "./src/index.html"
}),
new CleanWebpackPlugin() //打包以前 webpack的output.path目录中的全部文件都将被删除一次,目录自己不会
],
复制代码
mode: 'development';
devtool: 'cheap-module-eval-source-map';
//
mode: 'production';
devtool: 'cheap-module-source-map'
复制代码
source-map 生成一个map.js的文件
inline 将map.js文件注入到打包好的js文件
cheap:精确到多少行,而不关心多少列 ;不关心loader的错误;
module 不加module只关心本身的文件 不关心第三方文件 loader的错误映射
eval 以eval的形式注入到打包好的js文件中
//todo............
复制代码
// npm i webpack-dev-server -D
devServer: {
contentBase: './dist', //路径
open: true, //打开浏览器
proxy: { //代理转发 跨域
'./api': {
target: 'http://localhost:3000'
}
},
port: 8081 //修改默认端口
}
//===========================
"scripts": {
"bundle": "webpack",
"start": "webpack-dev-server"
}
复制代码
能够结合node.js webpackmiddleware 写一个本身的webpack-dev-server
webpack-dev-server会将打包好的文件存到电脑的内存中,提高打包速度。
需求:
当须要样式局部刷新不影响页面其余内容
const webpack = require('webpack');
devServer: {
contentBase: './dist',
open: true,
port: 8081,
hot: true, //开启HMR
hotOnly: true //当HMR没有起做用,也不用刷新页面
}
new webpack.HotModuleReplacementPlugin()
复制代码
当须要修改js文件而不影响其余的内容
if(module.hot) {
module.hot.accept('./demo', function () {
demo()
document.body.removeChild(document.getElementById('asd'))
})
}
复制代码
npm install --save-dev babel-loader @babel/core
@babel/core是babel的核心语法库 (这个loader只是将webpack和babel作了链接,并不会处理js文件,须要借助其余模块)
npm install @babel/preset-env --save-dev
。
@babel/preset-env
包含了全部es6-es5的规则。
{
test: /\.js$/,
exclude: /node-modules/, //exclude意思是在node-modules中的js文件不会去操做
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'] //还须要一个配置项
}
}
复制代码
需求:有些低版本的浏览器不兼容一些方法,变量等,如promise
,map
。须要借助babel-polyfill/core-js
作一个补充。
npm install @babel/polyfill
(已经淘汰)
最新:npm install core-js@3
业务代码中引入import '@babel/polyfill'/import 'core-js'
可是这么作会引入不少用不着的,如今想按需引入
这里讲一讲 useBuiltIns 配置
咱们可能在全局引入 babel-polyfill,这样打包后的整个文件体积必然是会变大的。
可是经过设置 "useBuiltIns": "usage"
可以把 babel-polyfill 中你须要用到的部分提取出来,不须要的去除。
useBuiltIns 参数说明:
优化
import 'core-js'
//入口文件引入
{
test: /\.js$/,
exclude: /node-modules/,
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', {
useBuiltIns: 'entry', //若是配置为usage 就没必要引入import 'core-js'
corejs: 3, //必须配置依赖的corejs
targets: {
chrome: '70'
}
}]]
}
}
复制代码
注意:以上方式是写业务代码时使用的。当开发类库,组件库时若是使用这种方式会将好比promise
注入到全局变量,污染全局变量
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
注意:@babel/runtime
as a production dependency
{
test: /\.js$/,
exclude: /node-modules/,
loader: 'babel-loader',
options: {
'plugins': [['@babel/plugin-transform-runtime', {
"absoluteRuntime": false,
"corejs": 3, //默认值false 是不会将ES6的语法打包的
"helpers": true,
"regenerator": true,
"useESModules": false
}]]
}
}
复制代码
corejs option |
Install command |
---|---|
false |
npm install --save @babel/runtime |
2 |
npm install --save @babel/runtime-corejs2 |
3 |
npm install --save @babel/runtime-corejs3 |
注意当文件过于复杂时:在根目录下建立.babelrc
文件
npm install @babel/preset-react
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "entry",
"corejs": 3,
"targets": {
"chrome": "70"
}}],
["@babel/preset-react"] // presets 中的内容是从后往前一次执行的,先执行@babel/preset-react
]
"plugins": ["@babel/plugin-proposal-class-properties"] //若是不配置没法使用箭头函数
}
复制代码
只支持ES Module(静态引入) require是动态引入 不支持!
按需引入某一模块中所须要的代码。
//好比一个文件内部暴露了两个方法,我在另外一个文件中只须要引入其中一个,可是webpack默认两个方法都会打包
mode: 'development' //默认没有开启Tree Shaking
//配置webpack.config.js,当mode为production时,不用配置这一项
{
optimization: {
usedExports: true
}
}
//配置package.json
{
"sideEffects": ["*.css","core.js"] 或者 false //过滤不须要Tree Shaking的文件
}
复制代码
写两套代码
{
"scripts": {
"dev": "webpack-dev-server --config webpack-dev-js",
"build": "webpack --config webpack-pro-js"
}
}
复制代码
问题:
这样带来了一个问题就是两个文件中有很是多的重复代码。
解决:
新建文件夹webpack.common.js
,使用webpack-merge
const merge = require('webpack-merge');
const common = require('./common')
const dev = {
...
}
module.exports = merge(common, dev)
复制代码
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
vendors: false, //前缀名
default: false
}
}
}, // 同步代码分割 webpack.config.js的配置项
复制代码
function getComponent() { //异步加载 代码分割 经过dynamic import
return import(/*webpackChunkName: 'lodash'*/'lodash').then(({ default: _ }) => {
return _
})
}
getComponent().then( _ => {
console.log(_.join(['a', 'b', 'c'], '%^'));
})
复制代码
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "entry",
"corejs": 3,
"targets": {
"chrome": "70"
}}],
"@babel/preset-react"
],
"plugins": ["@babel/plugin-syntax-dynamic-import"] //使用插件
}
复制代码
npm i -D @babel/plugin-syntax-dynamic-import`
/*webpackChunkName: 'lodash'*/
这个能够给打包的文件起名字
Webpack和Code Splitting的底层就是是用了SplitChunksPlugin这个插件。
//SplitChunksPlugin 默认配置
splitChunks: {
chunks: "async", //只对异步代码进行打包 可配置all(须要配置cacheGroups ) initial(同步)
minSize: 30000, //大于30kb作代码分割
minChunks: 1, // 被用了至少多少次才进行代码分割
maxAsyncRequests: 5, //同时加载的模块数至多5个,超过5个,超过的不会作代码分割了
maxInitialRequests: 3, //入口文件最大价值3个模块,超过3个,超过的不会作代码分割了
automaticNameDelimiter: '~', //组,文件链接符。
name: true,
cacheGroups: {
vendors: { //打包的文件属于vendors这个组。
test: /[\\/]node_modules[\\/]/, //检测须要打包的库是否在node_modules中
priority: -10, //优先级 vendors大于default
filename: 'vendors' // ‘vendors.js’
},
default: { //打包的文件属于default这个组。
minChunks: 2,
priority: -20,
reuseExistingChunk: true //若是一个模块被打包过 a,b,c c里面引入了a,b a里面又引入了b,则c直 接复用以前打包过的b,而不须要再次打包b
}
}
}
//同步代码打包的过程当中,知足前面的配置要求,不会直接作代码分割,而是放入cacheGroups中保存,在作判断是放入哪一个组里
//异步代码不用
复制代码
import
语法
每个打包出来的文件都是一个chunk
webpack --profile --json > stats.json
github.com/webpack/ana…
代码分析
浏览器查看代码使用率:network + ctrl + shift + p
webpack推荐多使用 异步加载的代码 import().then()
利用缓存提高页面性能是很是有限的,利用webpack的懒加载 + prefetch 极大的提高代码利用率,是很是好的提高页面性能的方案。
某些异步加载的代码,当首页彻底加载出来后,此时带宽彻底释放后,能够进行预加载。
prefetch
prefetch和preload的区别:
entry: {
main: './src/index.js'
}
output: {
filename: "[name].js", //main.js为主文件入口,走的filename这个配置项;
chunkFilename: "[name].chunk.js" //main.js中的按需加载的文件,走这个配置项。
}
复制代码
css的代码分割须要借助插件:
MiniCssExtractPlugin
缺点:不支持HMR,适合线上环境作打包。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, //替换成这个。
{
loader: "css-loader",
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
复制代码
optimize-css-assets-webpack-plugin
压缩打包后的css代码。
loading....