Webpack(笔记一)
简介:初识Webpack、Webpack核心概念、进阶、实战配置案例、webpack底层原理及脚手架工具分析
1.1 Webpack概念
- 定义:模块打包工具
- 几种引入规范:
1、ES Module 模块引入方式:
import export(构造函数)
2、CommonJS 模块引入规范:
require(跟Node一样)
module.exports
3、CMD
4、ADM
1.2 安装与使用
- 安装:
npm init 项目名
npm install webpack webpack-cli -D
- 使用(生成main.js):
npx webpack index.js
- 注:npx会帮我们在项目目录中的node_modules查找webpack
1.3 webpack配置
- 默认配置文件:webpack.config.js(需手动创建)。
const path = require('path');
module.exports = {
//配置模式,默认是production(会压缩js),可以是development(就不会压缩)
mode: 'production',
//entry表示文件打包的起点
entry: './index.js',
//output表输出
output: {
//表示打包后放置的js文件
filename: 'bundle.js',
//表示输出路径,要加绝对路径,所以引用path模块
path: path.resolve(__dirname, 'bundle')
}
}
- entry的值如果是一个文件路径,默认其Chunk Names为main,其值可以是一个对象的形式。
entry: {
main: './index.js'
}
- 也可以修改配置文件的名字
npx webpack --config webpackconfig.js
webpackconfig是想要的配置名
- 配置完成后,以后直接npx webpack即可对模块进行打包。也可以修改package.json的文件,修改指令。
package.json:
"script": {
"自定义": "webpack"
}
npm run 自定义
即可实现对模块进行打包(注意此处用npm即可)
1.4 配置打包其他文件(除js)
- 上边的webpack配置仅限于打包js文件,要配置打包其他类型的文件,用module配置。要安装file-loader或其他模块(vue-loader,url-loader)。
const path = require('path')
module.exports = {
mode: 'production',
entry: './index.js',
module: {
rules: [{
//正则式测试文件后缀
test: /\.jpg$/,
//使用对应API处理
use: {
loader: 'file-loader',
//保证打包后图片名字不变
options:{
//还有其他占位符,例如[hash]
name: '[name].[ext]',
//修改文件生成位置
outputPath: 'images/'
}
}
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'bundle')
}
}
- url-loader也可以用来处理图片,处理后返回的是一段base64格式写在js中的代码。(适用于比较小的图片的打包),使用limit限制打包图片的大小。
module: {
rules: [{
test: /\.jpg|.png|.gif$/,
use: {
loader: 'url-loader'
option: {
name: '[name].[ext]',
outputPath: 'images/',
//超过2kb的图片不会被打包
limit: 2048
}
}
}]
}
1.5 样式打包
- style-loader、css-loader、sass-loader和postcss-loder(css3自动添加厂商前缀,例如-webkit)。
- 至少要有style和css-loader,css-loader帮我们分析处理代码import各CSS模块间的关系,而style-loader则会将代码挂载到head中。
基本安装:
npm install style-loader css-loader -D
处理sass:
npm install sass-loader node-sass -D
处理css3(自动添加内核前缀):
npm install postcss-loader autoprefixer -D
需要配置postcss.config.js:
module.exports = {
plugins: [
require('autoprefixer')
]
}
- 多个loader使用时,是自下至上的,且use的值是一个数组。数据的item可以是各种loader或一个用于配置loader的对象。
webpack.dev.js:
(development开发模式下)
module: {
rules: [{
test: /\.scss$/,
//使用多个loader,use是个数组
use: [
//从下到上依次处理
'style-loader',
//要配置loader时,改为对象
{
loader: 'css-loader',
//保证二级引入的css也得到处理
options: {
importLoaders: 2,
//让css有模块的概念
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,
use: ['style-loader','css-loader','pstcss-loader']
}]
}
webpack.prod.js:
(上线打包时)
module: {
rules: [{
test: /\.scss$/,
use: [
//注意:此处替代了style-loader
//使得上线时CSS单独打包成独立文件
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'pstcss-loader'
]
}]
},
optimization: {
//对css文件进行压缩
minimizer: [new OptimizeCSSAssetsPlugin({})]
},
plugins: [
//引入和配置css处理插件
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
})
],
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
}
- 字体文件(iconfont)用file-loader处理即可。
2 使用plugins(插件)便捷打包
2.1 html-webpack-plugin
- 首先安装html-webpack-plugin,配置如下(载入并实例化),会使得npx webpack打包其他模块的同时,生成一个html页面(且自动引入js文件)。
webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//实例化的同时,配置html
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
})]
}
- 作用:可以在webpack运行到某个时刻的时候,帮你完成一些事(类似Vue中生命周期钩子)
2.2 clear-webpack-plugin(重建时,清空dist)
- 安装:clean-webpack-plugin -D
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
}), new CleanWebpackPlugin(['dist'])]
}
3 配置
3.1 Entry与Output的基础配置
- 打包多个js,entry和output配置。
- entry的值改为对象,键为文件名,值为相对路径下要打包的js。
- output配置:filename的值利用占位符[name],publicPath为传输地址。
module.exports = {
entry: {
main: './src/index.js',
other: './src/abc.js'
},
output: {
//配置传输地址(默认同级目录)
publicPath: 'http://cdn.com.cn'
//用占位符生成entry对应键名的js文件
filename: '[name].js'
path: path.resolve(__dirname,'dist')
}
}
3.2 SourceMap
- 作用:用于与生成的js形成映射关系,也就是能让页面告知是哪个具体的js文件哪行出错,而非直接告诉打包后的js文件哪行出错。
- 配置:
devtool:
'source-map':会生成一个map文件
或'inline-source-map':将map内容写入main.js中
或'cheap-source-map':跟第二个类似,不过它错误定位精确度比较低点,但速度是前三者最快的。
或'eval':最快的,但错误提示内容比较少。
上线(production)使用:'cheap-module-source-map':模块出错也会管理。
开发(development)过程:'cheap-module-eval-source-map'
3.3 WebpackDevServer
- 类似nodemon,当相关文件改变时,自动重新打包。利用webpack --watch
package.json:
"scripts": {
"watch": "webpack --watch"
}
运行:
npm run watch即可
- 使用devServer后打包的文件不会生成dist目录,而是放到内存中
- devServer配置服务器(放置文件、是否自动打开和端口号)
module.exports = {
// 服务器
devServer: {
//当访问api时会自动转到端口号3000的服务器上
proxy: {
'/api': 'http://localhost:3000'
},
//指定好服务器js文件放置位置
contentBase: path.join(__dirname, 'dist'),
//自动帮你打开浏览器和主页
open: true,
port: 8080
}
}
package.json:
"scripts": {
"start": "webpack-dev-server"
}
运行:
npm run start
或npx webpack-dev-server
- proxy配置项详细:
devServer: {
//代理请求转发
proxy: {
'/api': {
target: 'http:...',
//true时只对https生效
secure: false,
//能转换拿到demo.json
pathRewrite: {
'header.json': 'demo.json'
}
}
},
//拦截
bypass: function(),
//使得可以跨域访问
changeOrgin: true,
headers: {
host: 'www.xx.com',
cookie: 'xxxx'
}
}
3.4 Node.Js API
- node.js实现启动服务器时自动webpack打包
server.js:
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js');
//生成编译器,能自动执行打包
const complier = webpack(config);
const app = express();
//利用中间件webpackDevMiddleware
app.use(webpackDevMiddleware(complier, {
publicPath: config.output.publicPath
}))
app.listen(3000, () => {
console.log('Server is running')
})
运行:
node server.js
3.5 Hot Module Replacement(模块热替换)
- HMR:改变样式时,页面不会重新加载(导致动态添加节点小时),但样式能动态改变。方便调试样式。
//需要用到webpack
const webpack = require('webpack');
module.exports = {
devServer: {
proxy: {
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'dist'),
open: true,
port: 8080,
//让页面保持缓存状态
hot: true,
hotOnly: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(),
//配置使用该插件
new webpack.HotModuleReplacementPlugin()
]
}
- 有两个以上实例要发生变动时,利用module.hot使实例间互不影响。
Counter();
Number();
if(module.hot) {
//利用accept方法
module.hot.accept('./number.js', () => {
let temp = document.getElementById('number')
temp.remove()
Number();
})
}
3.6 Babel处理ES6语法
- 目的:将ES6的语法转化为ES5,利用babel-loader处理js文件,配置.babelrc文件处理ES6的新增方法。
.babelrc(写业务代码时用parsets配置):
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": "58",
"ie": "6"
},
"useBuiltIns": "usage",
"corejs": { "version": 3, "proposals": true}
}
]
]
}
.babelrc(写内库时,避免全局污染,用plugins):
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
- babel-loader安装与配置:
安装:
npm install --save-dev babel-loader @babel/core
起建立通信作用
npm install @babel/preset-env --save-dev
起转化作用
配置:
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
//配置preset
options: {
preset: ["@babel/preset-env"]
}
}]
}
- bebal-loader和babal/present-env只能转化部分语法,ES6的新方法则不行。还需要使用@babel/polyfill。
- @babel/polyfill在7.4.0中已弃用
https://babeljs.io/docs/en/babel-polyfill
安装:
npm install --save @babel/polyfill
配置:
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
//只打包用到的部分
useBuiltIns: 'usage'
}
]
]
}
}
使用(新版本已弃用):
import "@babel/polyfill";
或require("@babel/polyfill");
- 配置presets使用core-js(写业务代码时,平时项目使用)
安装:
npm install core-js@3 --save
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 控制最低浏览器版本号
{
'targets': {
'chrome': '58',
'ie': '6'
},
// 配置对有需要的代码进行转换
useBuiltIns:'usage',
corejs: { version: 3, proposals: true }
}
]
]
}
}
- @babel/plugin-transform-runtime(写内库时,防止全局污染)
https://babeljs.io/docs/en/babel-plugin-transform-runtime
安装:
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs3
配置:
options: {
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
- 可以把配置写成一个文件名为“.babelrc”的文件。这样就可以把option去除掉。
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}