webpack入门介绍
0、码云仓库代码(欢迎Start)
码云仓库代码-https://gitee.com/hongjunyong/webpack-imooc-test
1、基本介绍
webpack是为什么?
为什么要使用webpack?
怎么配置webpack?
1.1、webpack官方文档
https://doc.webpack-china.org/
https://github.com/webpack/webpack
1.2、webpack概述
js(ES6、typescript)的打包器、代码按需加载、loader加载器
webpack-detail.png
从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less(不仅仅这些,还有像jade、less等等)转换成一个静态文件,减少了页面的请求。
1.3、webpack版本变化
webpack v1.0.0 --- 2014.2.20 编译打包、模块热更新、代码分割、文件处理
webpack v2.2.0 --- 2017.1.18 打包文件体积更小、动态import、新的官方文档
webpack v3.0.0 --- 2017.6.19 作用域提升(打包后的代码性能)、配合动态import使用
webpack v4.0.0 --- 2018.2.27 打包的速度提升(构建时间降低了 60%-98%)、Mode 零配置以及默认值:development 或者是 production、entry默认:./src/index.js为入口文件,output默认:./dist/main.js
time.png
1.4、为什么webpack?
1、最热门的三大框架:vue、react、angular,他们命令行工具都使用webpack构建工具
Vue-cli
Angular-cli
React-starter
2、代码分割:Code-splitting
3、模块化(js模块化、css模块化【css设计模式,例如:SMACSS模式(减少代码量、简化代码维护)、oocss模式】)
1.5、hello webpack(案例:1-1-first)
demo.png1.6、安装
npm install webpack@3.10.0 -g
webpack4.0以上版本:npm install webpack-cli -g(交互式的初始化一个项目、迁移项目V1 -> V2[仅限配置文件])
二、核心概念
2.1、Entry :
功能:1、代码入口;
2、打包的入口;
3、单个(业务代码、框架代码分开)或多个(多页面程序)
示例:
写法一、
// 扩展性差
module.exports = {
entry: 'index.js'
}
写法二、
// 扩展性差(两个文件、两个路径)
module.exports = {
entry: ['index.js', 'vendor.js']
}
写法三(推荐)、
module.exports = {
entry: {
index: 'index.js',
vendor: 'vendor.js'
}
};
2.2、Output:
功能:1、打包成的文件(bundle);
2、一个或多个、自定义规则
示例:
// 一个入口对应一个出口
module.exports = {
entry: {
index: 'index.js',
},
output: {
filename: 'index.min.js'
}
};
module.exports = {
entry: {
index: 'index.js',
vendor: 'vendor.js'
},
// 例如:entry=index ==> index.min.js
// 例如:entry=vendor ==> vendor.min.js
// MD5:版本号
output: {
// 用于输出文件的文件名 MD5码(5代表有五位数)
filename: '[name].min.[hash:5].js'
// 目标输出目录 path 的绝对路径(此配置将一个单独的 bundle.js 文件输出到 /home/proj/public/assets 目录中)
path: '/home/proj/public/assets'
}
};
2.3、loader:
功能:1、处理文件;
2、转化为模块(例如loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript)
示例:(rules执行的顺序从下到上)
module.exports = {
module: [
rules: [
{
// 易错:这里的正则不带引用
test: /\.css$/,
use: 'css-loader',
// 排除在规则之外的
exclude: '/node_modules'
}
]
]
}
2.3.1、常用的loader
编译相关:
babel-loader、ts-loader
样式相关:
css-loader、style-loader、less-loader、postcss-loader
文件相关:
file-loader、url-loader
2.4、plugin:
功能:1、插件是 wepback 的支柱功能;
2、参与打包整个过程;
3、打包优化和压缩(打包公共代码,如果是多页面的程序,公用的代码会缓存到浏览器,减少对服务端的请求)
4、配置编译时的变量
示例:
// 压缩代码
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
}
2.4.1、常用的plugins
优化相关:
commonsChunkPlugin:提取不同chunk(提取公共代码,形成一个公共的代码块)
uglifyjsWebpackPlugin:压缩代码
功能相关:
extractTextWebpackPlugin:css提取出来作为一个单独的文件
htmlWebpackPlugin:生成html
hotModuleReplacementPlugin:模块热更新
copyWebpackPlugin:拷贝文件(例如引用别人的插件,别人已经压缩打包好了)
2.5、 名词解释
Chunk:代码块(提取公共代码,形成一个公共的代码块)
Bundle:一捆、一束:打包过的代码
Module:模块
3、webpack基本命令
webpack -h 查看所有命令
webpack -v 查看版本
webpack entry<entry> output 或 webpack --config webpack.conf.js 打包js
webpack-cli init webpack-addons-demo(webpack-addons前缀,demo项目名称): 交互式的初始化一个项目
webpack-cli.png
webpack-cli-pengwings.png
4、 实战
4.1、 打包js(案例:3-1-js 同 1-1-first)
打包:webpack app.js bundle.js(app.js代表入口文件;bundle.js代表打包后生成的文件)
webpack --config webpack.conf.js(文件名不是webpack.config.js,如果是的话,直接执行webpack命令)
4.2、 编译ES6(案例:3-2-es6) 略
npm init 项目初始化,添加package.json
npm install babel-loader@8.0.0-beta.0 @babel/core 静态文件托管
npm install @babel/preset-env --save-dev
4.3、 编译typescript(案例:3-3-typescript) 略
npm install webpack typescript ts-loader awesome-typescript-loader --save-dev
npm install typescipt ts-loader --save-dev
npm install typescipt awesome-typescript-loader --save-dev
如果项目中有用到lodash
npm install lodash --save
4.4、 打包公共代码(案例:3-4-public)
4.4.1、 作用
减少代码冗余
提高加载速度
案例:
public.png
把C提取出来:如果用户访问了A并且加载了C,再当用户浏览了B,C就不用再去加载
4.4.2、 应用场景:
单页面就不需要再去加载
多页面利用浏览器缓存
4.4.3、 使用的插件 commonsChunkPlugin
- 配置
4.4.4、 使用步骤
初始化:npm init
安装本地依赖:npm install webpack --save-dev
针对多个entry,如果只有一个entry是没有作用的(单页面更多的是用懒加载,懒加载有其他的打包方式)
// 打包公共代码(第三方依赖 与 业务代码 混在一起)
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
// 代码出现2次就进行打包
minChunks: 2
})
// 分离第三方依赖 与 分离业务代码
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
// 代码出现2次就进行打包
minChunks: 2,
// 需要指定要打包的公共代码
chunks: ['pageA','pageB']
}),
new webpack.optimize.CommonsChunkPlugin({
// vendor是第三方插件打包后的代码,manifest是自己封装的公共代码进行打包
names: ['vendor','manifest'],
// 把webpack的代码页打包进来,不需要在任何地方重复了
minChunks: Infinity
})
4.5、 代码分割 和 懒加载(案例:3-5-splice)
让用户浏览的时候加载更少的代码,用更短的时间看到页面
AMD:依赖前置,提前执行
CMD:尽可能懒执行
4.5.1、 使用场景
分离业务代码 和 第三方依赖
分离业务代码 和 业务公共代码 和 第三方依赖
分离首次加载 和 访问后加载的代码
4.5.2、 pageA.js案例
// 只有打包出一个pageA.bundle.js文件(混在一起)
import * as _ from 'lodash'
// ensure只是把lodash加载进来,并没有执行到lodash代码(lodash提取到vendor里)
require.ensure(['lodash'], function () {
// 这里才有执行到lodash代码
var _ = require('lodash');
_.join(['1', '2'], '3')
},'vendor');
// 提前include,这样moduleA就被提取到pageA.bundle.js里
require.include('./moduleA');
// 会生成subPageA.chunk.js、subPageB.chunk.js文件(但是moduleA没有被分离出来)
var page = 'subPageA';
if (page === 'subPageA'){
require.ensure(['./subPageA'], function () {
var subPageA = require('./subPageA')
},'subPageA');
} else if (page === 'subPageB') {
require.ensure(['./subPageB'], function () {
var subPageB = require('./subPageB')
},'subPageB');
}
4.6、 css style-loader(案例:3-6-style-loader)
帮助需要载入的页面创建style标签(也就是:使用<style>将css-loader内部样式注入到我们的HTML页面)
webpack是自下而上解析的,只有通过css-loader处理css后才能通过style-loader生成<style></style>标签
4.6.1 安装
npm install style-loader --save-dev
npm install css-loader --save-dev
4.6.2 配置
module: {
rules: [
{
test: /\.css$/,
use: [
{
// 放到HTML页面上
// useable可以动态让css插入或不插入页面中
loader: 'style-loader/useable',
options: {
// 让css代码插入到指定的DOM节点上(图1)
insertInto: '#app',
// 让样式结合到一个style标签上(图2)
singleton: true,
// css函数(图3、4、5)
transform: './css.transform.js'
}
},
{
// 把css交给css-loader,让他处理完js可以import css这块内容,再交给style-loader
loader: 'css-loader'
}
]
}
]
}
import base from './css/base.css'
// 使用base样式
base.use()
// 不使用base样式
base.unuse()
(图1)
style.png
(图2)
style2.png
(图3)
pc.png
(图4)
iphone.png
(图5)
transform.png
4.7 css css-loader
加载.css文件
4.7.1 安装
npm install css-loader --save-dev
4.7.1 配置
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
// 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件)
loader: 'css-loader',
options: {
// css被压缩(图1)
minimize: true,
// js代码中使用css样式(图2)
modules: true,
// 给class命名:路径 文件名 class名称 五位的编码(图3)
localIdentName: '[path][name]_[local]_[hash:base64:5]'
}
}
]
}
]
}
// css-loader要结合app.js:
var app = document.getElementById('app');
app.innerHTML = '<div class="'+ base.box +'"></div>'
(图1)
cssmin.png
(图2)
css-loader.png
(图3)
name.png
4.7 配置less/sass(案例:3-7-less-sass)
4.7.1 安装
npm install less-loader less --save-dev
//因为sass-loader依赖于node-sass,所以还要安装node-sass
npm install sass-loader node-sass --save-dev
4.7.2 配置
module: {
rules: [
{
test: /\.less$/,
use: [
{
// 放到HTML页面上
loader: 'style-loader',
},
{
// 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件)
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
}
]
}
4.8 提取css文件(案例:3-8-extract)
style-loader、css-loader、less、sass都是把样式打包到js文件里,并不是生成独立的css文件,
利用提取css文件,会在dist目录下生成app.min.css文件
4.8.1 安装
npm install extract-text-webpack-plugin webpack --save-dev
加载:var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
plugins: [
// 对(提取css文件)插件的调用
new ExtractTextWebpackPlugin({
// 打包后的名字
filename: '[name].min.css',
// 指定提取范围(如果是true是就把所有有引入的css文件都打包;如果是false,只会提取初始化的文件)
allChunks: false
})
]
use: ExtractTextWebpackPlugin.extract({
// 当不提取用什么方式加载到页面上(直接把样式插入到HTML页面上)
fallback: {
// 放到HTML页面上
loader: 'style-loader'
},
// 继续处理的loader
use: [
{
// 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件)
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
})
提取出来的代码不会在页面上引用,需要手动引入
<link rel="stylesheet" href="./dist/app.min.css">
4.9 PostCSS(案例:3-8-postcss)
Autoprefixer:自动添加css前缀
css-nano:优化、压缩css
css-next:使用未来的css语法(例如calc)
npm install postcss postcss-loader autoprefixer cssnano postcss-cssnext --save-dev
- 核心配置:
{
// 放在less或sass预处理语言之前
loader: 'postcss-loader',
options: {
// 表明接下来插件是给postcss用的
ident: 'postcss',
plugins: [
// require('autoprefixer')(),
// postcss-cssnext已经包含了autoprefixer
require('postcss-cssnext')()
]
}
}
// 未来的css语法:
:root {
--mainColor: red;
}
a {
color: var(--mainColor);
}
postcss.png
4.10 Tree Shaking(案例:3-8-tree-shaking)
摇树木(摇完叶子会掉下来):写项目的时候有的代码没有用到,项目上线的时候代码还存在,会存在资源浪费、等待时间加长
4.10.1 使用场景:
常规优化
引入第三方库的某一个功能
4.10.2 js Tree Shaking
// 对没有用到的js代码进行过滤
new webpack.optimize.UglifyJsPlugin()
-
未使用前
js-tree-shaking.png -
使用后(代码被压缩,且只能找到‘this is a’)
js-tree-shaking-result.png
4.10.3 css Tree Shaking
npm install purifycss-webpack glob-all --save-dev
// 要写在ExtractTextWebpackPlugin的后面
new PurifyCSS({
paths: glob.sync([
path.join(__dirname, './*.html'),
path.join(__dirname, './src/*.js')
])
}),
5.1 图片处理(案例:4-1-img)
5.1.1 css中引入的图片(npm isntall file-loader)
作用:如果没有引入,图片资源会找不到;同时图片资源没有被打包
{
test:/\.(png|jpg|jped|gif)$/,
use: [
{
// 引入的图片
loader: 'file-loader',
options: {
// 设置绝对路径(指定路径,例如图片路径为:aa/1.jpg)
// publicPath: 'aa/',
// 输出的路径放到dist目录下(暂时没用,因为默认放在dist目录下)
// outputPath: 'dist/',
// 图片会放在dist/assets/imgs里,如果没有设置true,会裸露在外面
useRelativePath: true
}
}
]
}
file-loader.png
5.1.2 base64编码(npm isntall url-loader)
{
test:/\.(png|jpg|jped|gif)$/,
use: [
{
// base64图片
loader: 'url-loader',
options: {
name: '[name]-min[hash:5].[ext]',
// 当图片大于多少K的时候,转换成base64 100000 10K
limit: 100000,
// 图片会放在dist/assets/imgs里,如果没有设置true,会裸露在外面
useRelativePath: true
}
}
]
}
5.1.3 压缩图片(npm isntall img-loader)
{
loader: 'img-loader',
options: {
pngquant: {
// 压缩图片比例
quality: 80
}
}
}
-
压缩前(图片文件比较大)
img-loader2.png
-
压缩后(图片文件比较小)
img-loader.png
5.1.4 自动合成雪碧图(npm isntall postcss-sprites)
多张图片合成一张,压缩的时候会根据图片的位置进行定位
sprite.png
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
// 自动合成雪碧图
require('postcss-sprites')({
// 指定输出的路径
spritePath: 'dist/assets/imgs/sprites'
}),
require('postcss-cssnext')(),
]
}
},
5.1.5 字体文件
test: /\.(eot|woff|woff2|ttf|svg)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].[ext]',
limit: 5000,
publicPath: '',
useRelativePath: true
}
}
]
}
5.1.6 处理第三方 JS 库
三种引入方式:外网引入、npm安装、文件引入
第一种:外网引入(直接写在页面上就可以使用)
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
第二种:npm安装:npm install jquery --save
// 在每一个模块注入$这个变量
new webpack.ProvidePlugin({
$: 'jquery'
}),
第三种:文件引入
- 两处的jquery要对应
// 在每一个模块注入$这个变量
new webpack.ProvidePlugin({
$: 'jquery'
}),
- 配合
// 解析路径
resolve: {
alias: {
// jquery$:把jquery解析到某个路径下
jquery$: path.resolve(__dirname, 'src/libs/jquery-2.1.1.js')
}
},
- app.js
$('div').addClass('new');
jquery.png
5.2 生成HTML
npm install html-webpack-plugin --save-dev
var HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
// 生成html
new HtmlWebpackPlugin({
// 生成后的文件名
filename: 'index.html',
// 指定页面进行生成
template: './index.html',
// 打包后的引用路径不会重复
inject: false
})
]
引入图片
npm install html-loader --save-dev
网友评论