原文链接:https://juejin.im/post/5cd3dba3f265da036f4e9a0e
终于忙完了论文,可以愉快的开始学习了,重拾起重学前端、webpack以及Vue的源码解读作为入职前的复习吧。整个webpack系列将分成五个大的部分进行,以webpack4.0为文档进行解读,从简单的概念解读到最后的实现。
整个知识点涉及范围:
使用loader来预处理文件,把不同的静态资源(模块的结尾不是js的模块)打包成js文件
npm install file-loader -D
module.exports = {
//打包项目的入口文件
entry: './src/index.js',
module:{
rules:[{
test:/\.(jpg|png|gif)$/,//打包以jpg、png、gif结尾的所有图片文件
use:{
loader:'file-loader',
options:{//placeholder 占位符
name:'[name]_[hash].[ext]',//保持原图片的名字+hash值和后缀,主要单引号
outputPath:'image/'//打包图片的位置
}
}
}]
}
}
url-loader基本能实现file-loader的打包功能,适用于小图片的打包
所以,当图片的大小小于limit值时会把图片打包成base64格式,大于limit值则按照file-loader打包成图片文件
npm install url-loader -D
module.exports = {
module:{
rules:[{//打包以jpg、png、gif结尾的所有图片文件
test:/\.(jpg|png|gif)$/,
use:{
loader:'url-loader',
options:{//placeholder 占位符
name:'[name]_[hash].[ext]',//保持原图片的名字+hash值和后缀,主要单引号
outputPath:'image/',//打包图片的位置
limit:2048
}
}]
}
}
需要使用css-loader、style-loader
实现方式:
npm install css-loader style-loader -D
module.exports = {
module: {
rules: [{//打包css文件
test:/\.css$/,
use:['style-loader','css-loader']
}]
}
}
需要使用sass-loader、node-sass
npm install sass-loader node-sass -D
module.exports = {
module: {
rules: [{
test: /\.scss$/,
use:['style-loader','css-loader','sass-loader']
}]
}
};
在配置中,有三个loader,执行顺序是从下到上,从右到左。在打包scss文件时,首先执行sass-loader:对sass翻译成css文件,在挂载到css-loader,最后style-loader.
为了兼容不同的浏览器,在写样式的时候需要加上适用不同浏览器的前缀,如-o、-webkit、-moz等
-安装loader实现:npm install postcss-loader autoprefixer -D
-在根目录创建postcss.config.js
moudle.exports ={
plugins:[
require('autoprefixer')
]
}
module.exports = {
module: {
rules: [{
test:/\.scss$/,
use:[
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader']
}]
}
}
modules:true
开启css的模块化打包,在引入的时候注意区分场景:scss文件通过import引入其他scss文件,导致打包的时候引入的scss文件打包错误
实现:importLoader:2
在webpack.config.js中添加loader的配置
module:{
rules:[{//打包scss文件
test:/\.scss$/,
use:[
'style-loader',
{
loader:'css-loader',
options:{
importLoaders:2,//index.scss中通过import引入其他的scss文件,引入的scss文件在打包的时候也将依次经过所有的loader
modules:true
}
},
'sass-loader',
'postcss-loader']
}]
}
在阿里巴巴矢量图标库中,把需要的字体图标下载到本地,解压。将iconfont.eot iconfont.svg iconfont.ttf iconfont.woff 四种图片文件放入到项目中,在src中新建一个放字体图标的文件夹font。将iconfont.css文件拷贝到项目中,修改对应字体的引用路径。
npm i file-loader -D
module.exports = {
...
module: {
rules: [{
test: /\.(eot|ttf|svg|woff)$/,
use:{
loader:'file-loader'
}
},
]
}]
}
}
如遇到json、scv、xml文件需要打包时,使用csv-loader 和 xml-loader实现。
module.exports = {
module: {
rules: [{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}]
}
}
loaders可以将各个类型的静态资源打包成webpack能处理的模块,而plugins有更强大的功能。它可以从打包优化和压缩,一直到重新定义环境中的变量。
plugin可以在webpack运行到某一个时刻,自动完成一些事情。
npm install html-webpack-plugin -D
在src中创建一个html的模板,在HtmlWebpackPlugin的配置中引入该模板,打包后生成和模板类似的html文件并引入打包的js文件。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js'
},
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
})]
}
先删除上一次打包的dist文件,再执行打包
npm install clean-webpack-plugin -D
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist']), // 在打包之前,可以删除dist文件夹下的所有内容
]
}
__webpack_public_path__ = myRuntimePublicPath
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
sub: './src/index.js'
},
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
}), new CleanWebpackPlugin(['dist'])],
output: {
publicPath: 'http://cdn.com.cn', //加入cdn地址
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
SourceMap是一个映射关系,打包文件和源文件的映射关系,用于开发者的调试。
在devtool中进行设置:devtool: 'source-map'
打包速度会降低,在dist里面会有map映射文件
常用设置devtool说明:
development环境推荐使用: devtool: 'cheap-module-eval-source-map'
production环境推荐使用: devtool: 'cheap-module-source-map'
场景:每次在src里编写完代码都需要手动重新运行 npm run bundle,如何自动解决?
-安装:npm install webpack-dev-server –D
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
port: 8080
proxy:{//配置跨域,访问的域名会被代理到本地的3000端口
'/api': 'http://localhost:3000'
}
}
}
{
"name": "banggan",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle": "webpack",
"watch": "webpack --watch",
"start": "webpack-dev-server",
},
}
npm run server
运行自己写的类似webpackdevserver的工具{
"name": "banggan",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle": "webpack",
"watch": "webpack --watch",
"start": "webpack-dev-server",
"server" : "node server.js"
},
}
npm install express webpack-dev-middleware -D
webpack(config)
const express = require('express'); //引入express
const webpack = require('webpack');//引入webpack
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js');//引入配置文件
const complier = webpack(config); //编译一次吗,打包一次代码
const app = express();//创建express实例
app.use(webpackDevMiddleware(complier, {}));
app.listen(3000, () => {//监听3000端口
console.log('server is running');
});
场景:在程序运行中。替换、添加、替换某个模块,不需要重新加载整个页面,实现交互时更新。
在 webpack.config.js 中,添加配置
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,//开启热更新功能
hotOnly: true//如果html功能没有实现,也不让浏览器刷新
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()//使用热模块插件
],
}
//如果模块启用了HMR,就可以用 module.hot.accept(),监听模块的更新。
if (module.hot) {
module.hot.accept('./library.js', function() {
// 使用更新过的 library 模块执行某些操作...
})
}
//拒绝给定依赖模块的更新,使用 'decline' 方法强制更新失败。
module.hot.decline(
dependencies // 可以是一个字符串或字符串数组
)
注意:引入css文件时,用框架Vue,React 时,不需要写 module.hot.accept(),因为在使用css-loader,vue-loader,babel-preset时,均配置好了HMR,不需要自己重新写
如果文件没有内置HMR,需要自己手动写监听模块更新代码
//preset-env语法转换
npm install babel-loader @babel/core @babel/preset-env -D
//兼容低版本浏览器的语法,函数的补充
npm install --save @babel/polyfill
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, //排除在外:在node_modules中的js,babel-loader不生效
loader: "babel-loader" ,
options:{
"presets": [["@babel/preset-env",{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},//运行在大于**版本的浏览器上,,已经支持es6的高浏览器不需要转换为es5
useBuiltIns:'usage' //按需添加polyfill,把业务代码中的新语法新函数都转成低版本浏览器兼容的
}]]
}
}
]
}
import "@babel/polyfill";
注意如果不是打包业务代码,而是写的类库、或者z组件库的时候不能使用@babel/polyfill实现,因为会导致声明的变量变成全局变量,污染全局环境。使用
plugin-transform-runtime
实现
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader" ,
options:{
"plugins": [["@babel/plugin-transform-runtime",{
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}]]
}
}
]
}
由于babel配置的内容较多,官网推荐在根目录下创建属于babel的配置文件.babelrc文件
由于babel需要配置的内容非常多,我们需要在项目根目录下创建一个 .babelrc 文件。
就不需要在 webpack.config.js 中写 babel 的配置了。
在 .babelrc 中:
{
"plugins": [["@babel/plugin-transform-runtime", {
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}]]
}
module.exports = {
mode: 'development', //开发环境进行打包,打包的代码不会压缩
devtool: 'cheap-module-eval-source-map',//不带列信息,只对业务代码进行sourcemap的生成
entry: {//配置入口文件
main: './src/index.js'
},
devServer: {//配置webpack,开发环境的调试
contentBase: './dist',//启动服务器的目录
open: true,//打开新的端口号8080
port: 8080,
hot: true,//打开热替换功能
hotOnly: true
},
module: {//对不同的文件进行打包规则
rules: [{
test: /\.js$/, //对js文件的babel-loader打包,其配置在.babelrc文件中
exclude: /node_modules/, //排除在外:在node_modules中的js,babel-loader不生效
loader: 'babel-loader',
}, {
test: /\.(jpg|png|gif)$/,//对图片进行打包
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240//小于10240以base64的形式进行打包
}
}
}, {
test: /\.(eot|ttf|svg)$/,//字体文件的打包
use: {
loader: 'file-loader'
}
}, {
test: /\.scss$/,//scss文件的打包,先用postcss-loader,在用sass-loader进行解析,最后css-loader进行挂载
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,//css文件的打包,没有sass-loader的解析
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist']),//自动清空上一次打包
new webpack.HotModuleReplacementPlugin()//热替换插件
],
output: {//出口文件
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}