本质上webpack是一个现代javascript应用程序的静态打包工具。
其它基础概念,查看官方文档
webpack 只能理解javascript和json文件。loader可以让它能够处理其他类型的文件,并将其转换有效模块。
两者主要功能都是对加载资源进行打包,但是 url-loader设置资源大小来对小资源进行打包js内,来减少网络带宽
module: {
// rules: [
// {
// test: /\.(png|jpg|gif)$/,
// use: {
// loader:'file-loader',
// options:{
// name:'[name].[ext]'
// }
// }
// },
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options:{
limit:138228 //资源大小
}
}
]
},
]
},
***?*最终在浏览器端可以看到打包后得资源路径变为 ‘data:image/png;base64…’
安装
npm i style-loader css-loader -D
使用
{
test:/\.css$/,
use:[
"style-loader",
{
loader:"css-loader",
options:{
importLoaders:2 //保证import 引入得样式会执行所有loader,
modules:true //样式模块化
}
}
] //注意loader 顺序
}
css-loader 用户处理.css 文件,style-loader用于对样挂在标签上。
注意loader顺序, loader是从下到上 从右到左开始加载。
file-loader 和 url-loader 可以接收并加载任何文件也包括字体.
{
test:/\.(eot|svg|ttf|woff)$/, //打包字体
use:["file-loader"]
},
可以在webpack 运行到某个时刻帮我们做一些事情比如:打包优化、资源管理、注入环境变量等。
plugins:[
new cleanWebpackPlugin(), //预先清理
new htmlWebpackPlugin({
title:'html plugin demo',
template:'index.html'
})
],
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
plugins:[
new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: ['You application is running here http://localhost:3000'],
notes: ['Some additionnal notes to be displayed unpon successful compilation']
},
onErrors: function (severity, errors) {
// You can listen to errors transformed and prioritized by the plugin
// severity can be 'error' or 'warning'
},
// should the console be cleared between each compilation?
// default is true
clearConsole: true,
// add formatters and transformers (see below)
additionalFormatters: [],
additionalTransformers: []
})
]
const WebpackBuildNotifierPlugin=require('webpack-build-notifier');
{
devServer:{
//...
quiet:true
},
plugins:[
new WebpackBuildNotifierPlugin({
title: "My Project Webpack Build",
// logo: path.resolve("./img/favicon.png"),
suppressSuccess: true
}),
]
}
sourceMap:
它是一个映射关系,可以找到打包后代码位置在打包前哪个位置.
配置
devtool:'source-map' //production 环境默认配置
记忆技巧
它帮我们启动一个简单web server,并有实时重新加载功能.
npm i webpack-dev-server -D
devServer:{
port:8080, //启动端口号
contentBase:'./dist', //从什么位置查找文件
open:true, //自动打开默认浏览器,并访问服务
proxy:{ //跨域代理
'/api':'http://localhost:3000'
},
historyApiFallback:true //开启浏览器路由
}
webpack-dev-middleware 是一个封装器(wrapper),它可以把 webpack 处理过的文件发送到一个 server。
npm install wepack-dev-middleware --save-dev
根目录新建server.js
/**
* 实现类似 devServer服务,作用:1.监听文件改变
* 1. 检测文件改变'
* 2. 读取webpack conifg 文件
* 3. 启动一个服务
* */
const express=require('express');
const webpackDevMiddleware=require('webpack-dev-middleware');
const webpack=require('webpack');
const config=require('./webpack.config.js');
const complier=webpack(config);
const app=express();
// 告诉 express 使用 webpack-dev-middleware,
// 以及将 webpack.config.js 配置文件作为基础配置
app.use(webpackDevMiddleware(complier,{
publicPath:config.output.publicPath
}));
app.listen(3000,()=>{
console.log('server at port 3000');
})
package.json
script:{
"server":"node server.js"
}
启动server
npm run server
它会在应用程序运行过程中,替换、添加或删除模块,而不需要重新加载整个页面。
const webpack=require('webpack');
devServer"{
hot:true, //启动热替换
hotOnly:true //当 hot不起作用时,浏览器也不会重新
}
plugins:[
new webpack.hotModlueReplacementPlugin()
]
分别创建webpack.dev.js 和webpack.prod.js用于表示开发环境和生产环境配置。
"script":{
"dev":"webpack-dev-server --config webpack.dev.js",
"build":"webpack --config webpack.prod.js"
}
我们还可以通过 webpack-merge 来将 dev 和pro 文件公共部分提取出来。
//webpack.dev.js
const merge=require('webpack-merge');
const commConfig=require('./webpack.comm.js');
const devConfig={
...
}
module.exports =merge(commConig,devConfig);
此特性可以把代码分离到不同的bundle中,然后可以按需加载或并行加载这些文件。
常用的代码分离方法有三种:
入口配置:使用 entry 配置手动地分离代码。
防止重复:使用 SplitChunksPlugin 去重和分离 chunk。
动态导入:通过模块中的内联函数调用来分离代码。
entry:{ //配置多个入口文件
index:'./src/index.js',
another:'./src/modleA.js'
},
通过配置多个入口文件,则可以生成多个chunk,但是如果每个入口文件(chunk)之间存在重复的模块,则会导致被重复引用进各个模块中。我们可以通过使用 SplitChunksPlugin 插件来移除重复模块。
该插件已经集成在webpack中,不需要再次安装,现在我们修改上面配置
module.exports = {
mode:'development',
entry:{
index:'./src/index.js',
// another:'./src/modleA.js' //去掉手动引入loadsh 的入口文件
},
optimization:{ //添加如下配置
splitChunks:{
chunks:'all'
}
},
}
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}).catch(err => 'An error occured while loading the component');
}
getComponent().then(component => {
document.body.appendChild(component);
})
//webpack.config.js
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
},
plugins: [
new cleanWebpackPlugin(),
new htmlWebpackPlugin({
template: 'index.html'
}),
],
懒加载可以帮助我们优化网页或应用程序提升加载速度。
modleA.js
console.log('this modlle A ');
export default ()=>{
console.log('button click hered');
}
index.js
function initComponent() {
var button = document.createElement('button');
var br = document.createElement('br');
button.innerHTML = 'click me!';
document.body.appendChild(br);
document.body.appendChild(button);
button.addEventListener('click', () => {
import(/* webpackChunkName: "modleA" */ './modleA').then(module => {
var print = module.default;
print();
});
})
}
initComponent();
在webpack中,所有都是模块化,因此模块与模块之间是独立的,如果我们想运行下面这样代码,此时就需要shim 配置全局变量
//juery.test.js
export defualt ()=>{
$('body').css('background':'green');
}
import $ from 'jquery'
import test from './juqery.test.js'
test();
配置webpack
const webpack=require('webpack');
plugins:[
new webpack.providePlugin({
$:'juqery'
})
]
//安装 webpack依赖
npm install --save-dev webpack webpack-cli
npm install --save-dev typescript ts-loader
项目根目录新建tsconfig.json文件
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true
}
}
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
entry:{
index:'./src/index.ts',
list:'./src/list.ts'
},
plugins:[
new HtmlWebapckPlugin({
fileName:'index.html',
chunks:['runtime','index'],
}),
new HtmlWebapckPlugin({
filename:'list.html',
chunks:['runtime','list'],
}),
]
关于配置函数化提取,和配置。
const makePlugins=(configs)=>{
const plugins=[
new CleanWebpackPlugin(['dist'],{
root:path.resolve(__dirname,'dist');
})
];
Object.keys(configs.entry).forEarch(item=>{
plugins.push(new HtmlWebapckPlugin({
fileName:`${item}.html`,
chunks:['runtime',item],
})
)
});
return plugins;
}
const config={
entry:{
index:'./src/index.ts',
list:'./src/list.ts'
},
};
config.configs=makePlugins(config);
module.exports= config;
源码
官方指南戳这里
//安装loader 和babel 核心库
npm install --save-dev babel-loader @babel/core
//语法转换库
npm install --save-dev @babel/preset-env
//添加webpack 配置
module:{
rules:[
{
test: /\.js$/,
exclude: /node_modules/,
use:{
loader: 'babel-loader',
options:{
presets:['@babel/preset-env']
}
}
}
]
}
到这里,es6语法基本可以转换,还是对于map、includes 等方法函数,没有转换,
如果要进行转换则需要babel-profill 使用流程如下:
npm install --save @babel/polyfill
import “@babel/polyfill”;
到这里,打包后的代码会被转化,但是babel-polyfill 里有所以规则导致打包后体积变很大,
如果我们只是想转换我们写的代码,则需要修改如下配置
options:{
presets:[
['@babel/preset-env',{
useBuiltIns:'usage'
}]]
}
使用 @babel/plugin-transform-runtime来进行转换
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2, //默认false
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
两者都能提升code coverage,prefetch 是指将来某个节点需要加载的资源;preload 是指当前可能需要加载的资源
import(/* webpackPrefetch: true */ 'LoginModal');
import(/* webpackPreload: true */ 'ChartingLibrary');
欢迎大家关注我的前端仓库,这里有数据结构、常见面试题、框架、书籍等学习总结,有问题也可以在仓库 issues 或 emil: [email protected]