- 一、Webpack介绍
- 相关知识
- 二、Webpack的安装及初始化
- 三、
package.json
配置 - 四、
webpack.dev.js
初步配置 - 五、处理JS文件
- 六、处理CSS文件
- 七、处理HTML文件(方法一,推荐)
- 八、处理HTML文件(方法二,不推荐)
- 九、处理图片
- 十、清理打包文件的插件
- 十一、实现热更新
- 十二、多入口程序构建
一、Webpack介绍
webpack是什么
- webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。
webpack的作用
- 打包(把多个文件打包成一个js文件,减少服务器压力、带宽)
- 转化(less/sass/ts)需要loader
- 优化(SPA越来越盛行,前段项目复杂度高,webpack可以对项目进行优化)
webpack的构成
- entry 入口
- output 出口
- module 模块
- plugins 插件
- devSever 开发服务器
- mode 开发模式 development/production
相关知识
低级错误
module.exports
误写为module.export
,导致打包时报错
path.join()
与path.resolve()
的区别
path
是node.js
的内置模块,提供了一些工具函数,用于处理文件与目录的路径。
__dirname
:获得当前执行文件所在目录的完整目录名,即绝对路径
path.join()
path.join()
方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。- 可以理解为
path.join()
是将各个path片段连接在一起,即进行字符串拼接,但是遇到..
还是会解析
path.join('/foo', 'bar', 'baz/asdf', 'quux');
// 返回: '/foo/bar/baz/asdf/quux'
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
path.resolve()
path.resolve()
方法会把一个路径或路径片段的序列解析为一个绝对路径。path.resolve()
会将/xxx
解析为绝对路径path.resolve()
将参数从右往左解析,直到构造完成一个绝对路径。
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'
npx 简介
npx 是跟随 npm@5.2.0 发布的,npm 5.2.0 以上版本中内置npx
npx是npm内置的包执行器,类似于 npm 简化了项目开发中的依赖安装与管理
之前我们可能会写这样的命令:
npm i -D webpack
./node_modules/.bin/webpack -v
有了 npx,你只需要这样
npx webpack -v
npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,
就会帮你安装, 这里的PATH 就是项目 node_modules
如果npm版本较低,可以全局安装 npm install -g npx
直接运行远端脚本
npx 甚至支持运行远程仓库的可执行文件
$ npx github:piuccio/cowsay hello
二、Webpack的安装及初始化
mkdir webpack4
cd webpack4
npm init -y
npm i webpack webpack-cli webpack-dev-server -D // 安装webpack
mkdir src
New-Item webpack.config.js
三、package.json
配置
...
"scripts": {
"dev": "npx webpack-dev-server --mode=development --hot --open", // 开发环境
"build": "npx webpack --mode=production" // 生产环境
},
...
四、webpack.dev.js
初步配置
const path = require('path')
module.exports = {
// 入口:有且可以有多个,数组形式
entry: {
main: ['./src/index.js']
},
// 打包环境:开发 & 生产
// mode: 'development',
// 出口:有且只能有一个
output: {
filename: '[name].[hash:8].js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/', //公共文件生成的地址
chunkFilename : '[name].chunk.js' //公共块生成的文件根据入口文件名字生成
},
// 本地服务器配置
devServer: {
contentBase: path.resolve(__dirname, 'dist'),//开启devserver后默认进入dist/index.html
overlay: true, // 全屏遮罩显示编译器错误或警告
}
}
五、处理JS文件
1. 安装babel
处理js文件我们需要用到babel,先安装一下
npm i babel-loader babel-core -D
2. 安装 babel-preset-env
和babel-preset-stage-0
npm i babel-preset-env babel-preset-stage-0 -D
babel-preset-env介绍
babel-preset-env
能根据当前的运行环境,自动确定你需要的 plugins 和 polyfills。
{
"presets": [
[
"env",
{
"targets": { // 配支持的环境
"browsers": [ // 浏览器
"last 2 versions",
"safari >= 7"
],
"node": "current" // 通过Babel编译你的Node.js代码,支持的是当前运行版本的nodejs
},
"modules": true,
"debug": true,
"useBuiltIns": false,
"include": [],
"exclude": []
}
]
],
plugins: []
}
target.browsers
: 指定相应的浏览器配置// 例子 "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
target.node
: 如果你通过Babel编译你的Node.js代码,targets.node: "current"
,支持的是当前运行版本的nodejsmodules
: 将ES6语法转换为另一种模块模型 可选值:”amd”、 “commonjs”、 “systemjs”、 “umd” 设置为false则禁止转译模块语法webpack已经把这个事情做了,所以就不需要babel来做了,但是babel配置项中的modules默认值是commonjs,所以你需要将modules设置为false才行,不然就冲突了。
include
: 必须要转译的功能,跟单独启用相应插件是一样的。exclude
: 禁止转译的功能useBuiltIns
:默认值: false。设置为true可以实现babel-preset-env
基于特定环境引入需要的polyfill。// 使用方法 npm i babel-polyfill // 安装 polyfill import 'babel-polyfill // 在入口js处引入
最终都会根据环境转译成特定的polyfill。 比如:
require('core-js/modules/es6.typed.array-buffer'); require('core-js/modules/es6.typed.int8-array');
在整个应用里只能引入一次polyfill,可以在
index.js
里一次引入。
useBuiltIns
会使浏览器下载的代码变少 (最终打包的文件大小变小了)。但是不会节约内存, 因为polyfill本身只会安装缺少的部分。debug
: 默认为false,设置为true则console.log输出目标环境、启用的transforms、启用的plugins、启用的polyfills
babel-preset-stage-0是对 ES7 支持的插件
3. 浏览器兼容及性能问题
为防止浏览器不支持 Promise/Object.assign/Array.from等还有性能问题,我们引入babel-polyfill
和babel-plugin-transform-runtime
:
npm i babel-polyfill babel-runtime -S
npm i babel-plugin-transform-runtime -D
在入口文件引入babel-polyfill
import 'babel-polyfill'
4. 配置.babelrc
在根目录下创建.babelrc
{
"presets": [
["env", {
"modules": false, // 设置为false禁止转译模块语法
"debug": true,// 开启debug模式,编译时会显示配置的信息
"targets": {
// 配置浏览器支持信息
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
},
"useBuiltIns": true // 引入需要的polyfill而不是全部
}],
"stage-0" // es7支持
],
"plugins": ["transform-runtime"]
}
5. 配置加载器(loader)
// js loader
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
include: path.resolve(__dirname , 'src'),
exclude: /node_modules/
}
]
}
六、处理CSS文件
1. 安装处理CSS相关loader
npm i css-loader style-loader -D
css-loader
: 能让你import cssstyle-loader
: 能将css以style的形式插入
2. 安装postcss
和autoprefixer
添加浏览器前缀(或者postcss-cssnext)
npm i postcss-loader autoprefixer -D
//第二种方法
npm i postcss-loader postcss-cssnext -D
创建postcss.config.js
,加入以下代码
module.exports = {
plugins: [
require('autoprefixer')()
]
}
// 第二种方法
module.exports = {
plugins: [
'postcss-cssnext': {}
]
}
4. 安装生成单独CSS插件和热更新loader
npm i mini-css-extract-plugin css-hot-loader -D
// npm i extract-text-webpack-plugin@next -D
// 注意extract-text-webpack-plugin 必须下载next版本 不然不支持webpack4
5. 配置加载器(loader)和插件(plugins)
// const ExtractTextWebapckPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
...
// css loader
{
test: /\.css$/,
use: [
'css-hot-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
// use: ExtractTextWebapckPlugin.extract({
// use: ['css-loader','postcss-loader']
// })
},
...
plugins:[
...
new MiniCssExtractPlugin({
filename:'style.[hash:8].css'
})
]
6. 在src/index.js
CSS
require('./style.css')
...
七、处理HTML文件(方法一,推荐)
1. 安装插件
npm i html-webpack-plugin -D
2. 配置插件(plugins)
const HtmlWebpackPlugin = require('html-webpack-plugin');
...
plugins:[
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src','index.html'),//模板
filename:'index.html', // 文件名
hash:true,//防止缓存
minify:{
removeAttributeQuotes:true//压缩 去掉引号
}
}),
]
八、处理HTML文件(方法二,不推荐)
1. 在src/index.js
内引入html
require('./index.html')
...
2. 安装相关加载器(loader)
npm i file-loader extract-loader html-loader -D
3. 配置加载器(loader)
// html loaders
{
test: /\.html$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
},
{
loader: 'extract-loader'
},
{
loader: 'html-loader',
options: {
attrs: ["img: src"] // 配置加载图片
}
}
]
}
九、处理图片
1. 常见的三种加载图片的方式
- css中引入
#wrapper {
background-image: url('./image/1.jpg);
}
- js动态引入
let imgSrc = require('./images/1.png');
let img = new Image();
img.src = imgSrc;
document.getElementById('root').appendChild(img);
- html img 标签
<img src="./image/1.jpg" alt="">
2. 前两种加载方式的处理
npm i file-loader url-loader -D
...
{
test:/\.(jpg|png|gif|svg)$/,
use:'url-loader?limit=8192&name=[name].[hash:8].[ext]&outputPath=images/',
include:path.join(__dirname,'./src'),
exclude:/node_modules/
}
3. 第三种加载方式的处理
使用html-loader进行处理
npm i html-loader -D
...
{
test: /\.(htm|html)$/,
use: 'html-loader'
}
十、清理打包文件的插件
安装插件
npm i clean-webpack-plugin -D
配置插件
const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
...
new CleanWebpackPlugin(['dist'])
]
十一、实现热更新
devServer: {
// ...
hot: true,
open: true
},
plugins: [
// ...
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
]
十二、多入口程序构建
需求:如何让对应的入口文件的html模版文件,引入只与本模块有关的js/css 。
1、在entry
添加对应的模块入口
entry:{//入口文件
pagea:'./src/pagea/index.js',
pageb:'./src/pageb/index.js'
}
2、如何让对应的入口文件的html,引入只与本模块有关的js
通过 html-webpack-plugin
解决。首先配置多个 html-webpack-plugin
实例对象,然后指定每个实例对象需要引入的 chunks
文件即可。
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src','index.html'),//模板
filename:'pagea.html',
chunks:['pagea'],
minify:{
removeAttributeQuotes:true//压缩 去掉引号
}
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src','index.html'),//模板
filename:'pageb.html',
chunks:['pageb'],
minify:{
removeAttributeQuotes:true//压缩 去掉引号
}
})
当需要引入多个的时候只需要在数组里面添加对应的模块名称即可。