webpack 4x
中文文档:https://www.webpackjs.com/concepts/
网页中的静态资源
- js : .js .jsx(react).coffee .ts(Typescript 类 c#语言)
- css: css .less .sass(基本没用了) .scss
- Images
- 字体模板
- 模板文件 : .ejs .jsde .vue
静态资源多了有什么问题?
- 网页加载速度慢, 因为 我们要发起很多的二次请求;
- 要处理错综复杂的依赖关系
如何解决上述两个问题
- 合并、压缩、精灵图、图片的Base64编码
- 可以使用webpack可以解决各个包之间的复杂依赖关系;
压缩合并工具:
- gulp是基于task任务的 (小乔,灵活,便于小项目的构建)
- webpack 基于整个项目构造()
简介
webpack是前端的一个项目构建工具,它基于Node.js开发出来的一个前端工具
注意
es6语法浏览器无法识别,得降低版本
能做什么?
- 能处理js文件的互相依赖关系
- 能处理js的兼容问题,把高级的、浏览器不识别的语法,转为低级的,浏览器能正常识别的语法
安装webpack
先全局安装
- 安装:
npm install -g webpack - 安装脚手架:
npm install -g webpack-cli - 也可以一次安装两个:
yarn add webpack webpack-cli - 检查版本号(没有版本号代表安装失败):
webpack -v
再局部安装
- 安装:
npm install webpack -D - 安装脚手架:
npm install webpack-cli -D - 也可以一次安装两个:
yarn add webpack webpack-cli -D(-D就是--save-dev 。-S就是--save)
动手:
最简单的打包,使用默认0配置,啥都不配置。
- 新建一个项目文件,
yarn init -y,初始化默认包配置文件 - 局部安装webpack
yarn add webpack webpack-cli -D - 新建src文件夹,里边新建一个index.js,随便编写脚本文件
npx webpack,发现会有一个dist目录生成,里边有一个压缩过的main.js- 在src和dist中分别创建一个index.html引入各自的js。分别在浏览器中打开。
知识点:
-
npx是npm v5.2引入的一个命令,npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装!
-
压缩过的js会多出很多代码,为什么?
- 打包,默认支持js的模块化,多出来的很多东西是关于模块化的兼容
-
dist中html在浏览器中能正常输出,src中的html却会报错‘require is not defined’,为什么?
- dist中的打包出来的代码,模块化相关的东西是经过兼容处理的,所以不会报这个错
- src里边的代码没有引入模块化相关的js文件,所以会报错。
- 但是在命令行中用node执行是不会报错的,因为node环境中有模块化相关的js文件
手动配置webpack
默认webpack的配置文件时webpack.config.js。名字是死的,
webpack-cli/bin/config-yargs.js中搜索webpack.config.js,默认有两个名字可以用
出口入口和模式
let path = require('path');//模块用于处理文件与目录的路径
module.exports = {
mode:'development',//打包模式:开发或生产
entry:'./src/01.js',//目标文件
output:{
filename:'bundle.js',//输出的名字
path:path.resolve(__dirname,'build')//必须是绝对路径:
//publicPath:'https://static2.yscase.com/'//把所有路径都加上cdn前缀地址
//node的path对象的resolve方法可以把当前路径转为绝对路径
//__dirname:当前模块的目录名
//参考说明:http://nodejs.cn/api/path.html#path_path_resolve_paths
}
}
自定义的配置文件名字
如:webpack.config.my.js
执行时,要这样执行:webpack --config webpack.config.js
配置package.json脚本
如果嫌弃命令语句太长,可以在package.json里添加脚本语句
xxxxxxxxxx
"scripts":{
"build":"webpack --config webpack.config.my.js"
},
执行yarn run build
webpack-dev-server
启动一个服务器,在服务器上预览
-
安装
yarn add webpack-dev-server -D -
配置
xxxxxxxxxxdevServer:{progress:true,contentBase:'./build',//指定文件夹port:3000,//设置端口号compress:true,//压缩}, -
添加到脚本
xxxxxxxxxx"scripts": {"dev": "webpack-dev-server"} -
执行yarn run dev
html打包
html-webpack-plugin(插件)
会自动引入js
普通单页面
-
安装插件
yarn add html-webpack-plugin -D -
配置package,添加脚本
xxxxxxxxxx"scripts": {"build": "webpack",}, -
配置插件(你的第一个插件)
-
先在顶部引入
xxxxxxxxxxlet HtmlWebpackPlugin = require('html-webpack-plugin');//打包html -
xxxxxxxxxxplugins:[new HtmlWebpackPlugin({template:'./src/index.html',//要打包的htmlfilename:'index.html',//输出的文件名minify:{removeAttributeQuotes:true,//删除双引号collapseWhitespace:true,//删除换行和空格},hash:true//hash随机数,给引用文件添加版本号})]
-
-
压缩html
xxxxxxxxxxnew HtmlWebpackPlugin({minify:{removeAttributeQuotes:true,//删除双引号collapseWhitespace:true,//删除换行和空格},}) -
hash戳解决缓存问题
-
给引用文件添加版本号
xxxxxxxxxxnew HtmlWebpackPlugin({hash:true//hash随机数,给引用文件添加版本号}) -
文件名添加hash
xxxxxxxxxxoutput:{filename:'bundle.[hash:8].js',//输出的名字},//加:8代表只显示8位hash值
-
-
执行
yarn run build
多页应用打包
有各自的html和入口js文件
xxxxxxxxxx
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode:'development',
entry:{ //多页时,写成对象模式,起个名字
home:'./src/index.js',
share:'./src/share.js'
},
output:{
filename:'[name].js', //此时name为入口时起的名字
path:Path.resolve(__dirname,'dist')
},
plugins:[
//HtmlWebpackPlugin插件有几个页面就实例化几个
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['home']//指定入口文件
}),
new HtmlWebpackPlugin({
template:'./src/share.html',
filename:'share.html',
chunks:['share']//指定入口文件
})
]
}
样式打包
打包css,less
打包css,less(less-loader),sass等
-
安装依赖
yarn add css-loader style-loader -D -
webpack‘配置文件,
xxxxxxxxxxmodule:{rules: [{test: /.css$/,use: [{ loader: "style-loader" },//写成对象时可以配置参数"css-loader" ,//直接写字符串不能配置参数],}],} -
css-loader:解决@import
-
style-loader:把css内容嵌入html
-
注意,use数组元素执行顺序是后往前,先css-loader,再style-loader
-
如是less
x{test: /.less$/,use: ["style-loader","css-loader" ,"less-loader" ,]}
分离css
-
安装mini-css-extract-plugin插件
yarn add mini-css-extract-plugin -D -
是插件,就要在顶部引入
xxxxxxxxxxlet MiniCssExtractPlugin = require('mini-css-extract-plugin');//分离css -
配置插件参数
xxxxxxxxxxnew MiniCssExtractPlugin({//filename:'main.css',//输出的文件名filename:'css/main.css',//输出到指定文件夹}) -
把原来的style-loader替换成MiniCssExtractPlugin.loader,原来的style-loader用于把css嵌入html,现在不需要了,而是,MiniCssExtractPlugin会生成一个link标签且分理处一个css文件,在html中引用
xxxxxxxxxx{test: /.css$/,use: [MiniCssExtractPlugin.loader,"css-loader",]}, -
如是less文件的页同理
xxxxxxxxxx{test: /.less$/,use: [MiniCssExtractPlugin.loader,"css-loader" ,"less-loader" ,]}
给css,less添加前缀
postcss-loader 用来处理css优化的 autoprefixer是其中一种优化:添加浏览器前缀
-
安装
yarn add postcss-loader autoprefixer -D -
css-loader之前执行
xxxxxxxxxx{test: /.css$/,use: [MiniCssExtractPlugin.loader,"css-loader","postcss-loader",//一定放在css-loader后面,才会先执行],}, -
如是less
xxxxxxxxxxuse: [MiniCssExtractPlugin.loader,"css-loader" ,"postcss-loader",//less-loader之后执行,css-loader之前执行"less-loader" ,], -
添加postcss配置文件postcss.config.js
-
xxxxxxxxxxmodule.exports = {plugins:[require('autoprefixer')]} -
注意:请尽量在js中引入css或less,如果在css或less中引入css或less,@import导入的内容不会被自动添加浏览器前缀!
压缩css
把mode设置为production,webpack打包一下,会发现js会自动压缩,但css不会
-
安装所需要的模块
-
把mode设置为production生产模式
-
配置文件顶部引入模块
yarn add optimize-css-assets-webpack-plugin UglifyJsPlugin -Dxxxxxxxxxx//压缩cssconst OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");//用于压缩js,如果要压缩css就必须添加压缩js的,否则js将不会压缩,const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); -
配置参数
xxxxxxxxxxoptimization: {minimizer: [//压缩jsnew UglifyJsPlugin({cache: true,//缓存parallel: true,//是否并发打包sourceMap: true // 高级js 转es5会用到 source maps}),//压缩cssnew OptimizeCSSAssetsPlugin({})]}, -
执行
yarn run build查看build文件夹中js和css是否都是压缩的
图片资源打包
file-loader
官网https://webpack.js.org/loaders/file-loader/
html-withimg-loader
js中引用的图片,css中的背景图片,html中的img标签图片,
file-loader匹配出找所有的图片,创建一个新的图片到指定目录,默认会生成新的带hash值的名字
-
安装本地依赖
yarn add file-loader -D -
配置loader
xxxxxxxxxx{test: /.(png|jpg|gif)$/,use: 'file-loader'}, -
读取图片
-
js中的图片
-
需要通过引入(import或require),才会被打包成新的图片
xxxxxxxxxximport girl from './girl.jpg';//引入图片console.log(girl);//新的图片路径let img = new Image();img.src = girl;document.body.appendChild(img);
-
-
css中的背景图片
- 使用了css-loader的话,css中的背景图片都能显示正常,因为css的路径都会被转为
url(require("./logo.png")),这样就会主动去生成新的路径并直接返回了
- 使用了css-loader的话,css中的背景图片都能显示正常,因为css的路径都会被转为
-
html中的图片
-
默认html中的图片不会被打包,因为没有被依赖,没有通过引入(import或require)
-
我们需要安装一个新的loader,用来解决这个问题
yarn add html-withimg-loader -D -
在loader中添加规则
xxxxxxxxxx{test: /.html$/,use: 'html-withimg-loader'},
-
-
-
打包执行
yarn run build
输出到指定文件夹
xxxxxxxxxx
{
test: /.(png|jpg|gif)$/,
use: {
loader:'file-loader',
options:{
limit:1,//小于最小体积就转为base64
outputPath:'img/',//指定文件夹
name:'[name]-[hash:6].[ext]',//名字
//publicPath:'https://static2.yscase.com/'//把所有图片都加上cdn前缀地址
}
}
}
高级js转es5
babel官网:https://babeljs.io/docs/en/
配合官网文档,更细致,在打包报错时,会有报错提示,看提示是缺少什么插件(包/模块),我们就去官网上搜索,查看使用
基本的es6
@babel/core是babel-loader的核心,
@babel/preset-env处理转化
声明语句,箭头函数,class类
babel-loader
@babel/core
@babel/preset-env
-
安装
yarn add babel-loader @babel/core @babel/preset-env -D -
添加规则
xxxxxxxxxx{test: /.js$/,exclude: /(node_modules|bower_components)/,//匹配时排除该文件夹use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env'] //预设}}}
class类静态属性
plugin-proposal-class-properties
https://babeljs.io/docs/en/next/babel-plugin-proposal-class-properties.html
-
安装针对class类的转化
yarn add @babel/plugin-proposal-class-properties -D -
添加插件配置
xxxxxxxxxxuse: {loader: 'babel-loader',options: {presets: ['@babel/preset-env'],plugins:['@babel/plugin-proposal-class-properties' //针对class]}} -
执行
yarn run build
装饰器
plugin-proposal-decorators
-
安装依赖
yarn add @babel/plugin-proposal-decorators -D -
用法:https://babeljs.io/docs/en/babel-plugin-proposal-decorators注意babel插件plugins顺序
xxxxxxxxxxoptions: {presets: ['@babel/preset-env'],plugins:[["@babel/plugin-proposal-decorators", { "legacy": true }],//宽松模式["@babel/plugin-proposal-class-properties", { "loose" : true }]]}
transform-runtime
如果你用了generator函数,打包时没有报错,但是打包后的代码在浏览器中却是报了错regeneratorRuntime is not defined
此时你还需要安装@babel/plugin-transform-runtime,帮助转化的包
plugin-transform-runtime还可以优化代码,减少重复的代码
-
安装开发时的依赖
yarn add @babel/plugin-transform-runtime -D -
安装生产上线时的依赖
yarn add @babel/runtime -S -
添加到babel依赖插件中
xxxxxxxxxxplugins:[["@babel/plugin-proposal-decorators", { "legacy": true }],//宽松模式["@babel/plugin-proposal-class-properties", { "loose" : true }],"@babel/plugin-transform-runtime"] -
执行打包
yarn run build
更高级的语法
This means you can use new built-ins like
PromiseorWeakMap, static methods likeArray.fromorObject.assign, instance methods likeArray.prototype.includes, and generator functions (provided you use the regenerator plugin).源自babel官网: https://babeljs.io/docs/en/babel-polyfill#docsNav
@babel/polyfill
-
安装生产上线时的依赖
yarn add @babel/polyfill -S -
js入口顶部引入
require("@babel/polyfill");import "@babel/polyfill";
-
执行打包,打包后的页面在ie中也能正常执行,没有使用这款插件的在低版本浏览器会报错的
ESLint高级js语法检验
暴露全局变量
require引入的是在当前模块,并不是全局,如要暴露给全局,如下
expose-loader
expose-loader暴露给全局(目前juqery已经是全局的了,再次只是比如)
-
安装expose-loader
yarn add expose-loader -D -
使用
-
引入时设置变量
import $ from 'expose-loader?$!jquery' -
webpack配置添加匹配规则
{ test:require.resolve('jquery'), //详解见http://nodejs.cn/api/modules.html#modules_require use:[{ loader:'expose-loader', options:'$'//暴露出来的全局变量 }] },
-
-
打包运行
ProvidePlugin
ProvidePlugin在每个js模块中引入插件
-
先引入
const Webpack = require('webpack') -
再配置插件
new Webpack.ProvidePlugin({ $:'jquery', jquery:'juqery' }) -
打包运行
webpack常用配置
sourcemap源码映射
打包后的代码都被压缩了,浏览器上不好找到报错的地方,我们可以通过sourcemap找到报错的地方行和列
官网文档:https://webpack.js.org/configuration/devtool/#devtool
module.exports = {
mode:'production',
//源码映射,会单独生成一个sourcemap文件,浏览器调试时出错会标识列和行
devtool:'source-map',
//源码映射,不会产生单独的文件,但是浏览器调试时可以显示行和列
devtool:'eval-source-map',
// 不会产生列,但是是一个单独的映射文件
devtool:'cheap-module-source-map',
}
watch
实时打包更新
常用插件
cleanWebpackPlugin
打包前清空文件夹https://www.npmjs.com/package/clean-webpack-plugin
-
先安装
yarn add clean-webpack-plugin -D -
引入插件
const CleanWebpackPlugin = require('clean-webpack-plugin'); -
plugins:[ new CleanWebpackPlugin('./dist')//传入要清空的文件夹,也可以是数组 ],
copyWebpackPlugin
复制文件到指定目录
-
先安装
yarn add copy-webpack-plugin -D -
引入插件
const CopyWebpackPlugin = require('copy-webpack-plugin'); -
plugins:[ new CopyWebpackPlugin([ {from:'./other',to:'./other'}//从根目录到输出目录 ]) ],
bannerPlugin 内置
给打包后的文件顶部嵌入标识语句,
-
webpack内置插件,引入webpack即可
const Webpack = require('webpack'); -
new Webpack.BannerPlugin({ banner:'2019.2.13by xiaoyue'//指定内嵌语句 })