系统学习webpack篇

文章目录

  • webpack 是什么?
  • webpack 基础篇
    • loader
      • file-loader & url-loader
      • style打包
      • 字体打包
    • plugin
    • 开发环境(devtool)
      • 其它参数
    • webpackDevServer
      • webpack-dev-middleware
    • 模块热替换(hot module replacement)
  • webpack 提升篇
    • development 和 production 模块区分打包
      • weback-merge使用
    • Code Splitting(代码分割)
      • 使用入口配置
      • 防止重复(SplitChunksPlugin)
      • 动态导入
    • lazy Loading(懒加载)
    • shim 预置依赖
    • 配置 typescript
      • tsconfig 配置
      • webpack 配置
    • 配置多页面
  • 杂记
    • webpack 配置es6语法
      • 解决babel-polyfil 污染全局环境问题
    • prefetch 与preload
      • 两者对比

webpack 是什么?

本质上webpack是一个现代javascript应用程序的静态打包工具。
其它基础概念,查看官方文档

webpack 基础篇

loader

webpack 只能理解javascript和json文件。loader可以让它能够处理其他类型的文件,并将其转换有效模块。

file-loader & url-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…’

style打包

安装

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"]
 },

plugin

可以在webpack 运行到某个时刻帮我们做一些事情比如:打包优化、资源管理、注入环境变量等。

  • html-webpack-plugin
    • 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中.
  • clean-webpack-plugin
    • 在打包之前,帮助我们删除dist目录
  plugins:[
    new cleanWebpackPlugin(), //预先清理
    new htmlWebpackPlugin({
      title:'html plugin demo',
      template:'index.html'
    })
  ],
  • friendly-errors-webpack-plugin
    它可以识别某些类别的webpack错误,并清理,聚合和优先级,以提供更好的开发人员体验。
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: []
          })
]
  • webpack-build-notifier
    它使用节点通知程序模块显示Webpack构建错误和警告的操作系统级别通知。
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
          }),
  ]
}

开发环境(devtool)

sourceMap:
它是一个映射关系,可以找到打包后代码位置在打包前哪个位置.
配置

devtool:'source-map' //production 环境默认配置

其它参数

  • cheap-module-eval-source-map
    • 适合 dev环境
  • cheap-module-source-map
    • 适合开发环境

记忆技巧

  • *-source-map
    参数中带有 source-map的则都具有映射关系,打包后会生成.map文件
  • inline-*
    参数中带有 inline 的,会将.map文件和并到打包文件中.
  • cheap
    • 提示行不提示具体那一列出错,不提示module(第三方模块)里的错误
  • module
    • 带有modlue 的则会提示引入模块错误信息.
  • eval
    • 通过eval 生成source-map引入.

webpackDevServer

它帮我们启动一个简单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

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

模块热替换(hot module replacement)

它会在应用程序运行过程中,替换、添加或删除模块,而不需要重新加载整个页面。

  • 保留在完全重新加载页面期间丢失的应用状态
  • 只更新变更内容
  • 在源码对css/js进行修改,会立即在浏览器中进行更新
const webpack=require('webpack');
devServer"{
  hot:true, //启动热替换
  hotOnly:true //当 hot不起作用时,浏览器也不会重新
}
plugins:[
  new webpack.hotModlueReplacementPlugin()
]

webpack 提升篇

development 和 production 模块区分打包

分别创建webpack.dev.js 和webpack.prod.js用于表示开发环境和生产环境配置。

"script":{
  "dev":"webpack-dev-server --config webpack.dev.js",
  "build":"webpack --config webpack.prod.js"
}

weback-merge使用

我们还可以通过 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);

Code Splitting(代码分割)

此特性可以把代码分离到不同的bundle中,然后可以按需加载或并行加载这些文件。
常用的代码分离方法有三种:

入口配置:使用 entry 配置手动地分离代码。
防止重复:使用 SplitChunksPlugin 去重和分离 chunk。
动态导入:通过模块中的内联函数调用来分离代码。

使用入口配置

   entry:{ //配置多个入口文件
    index:'./src/index.js',
    another:'./src/modleA.js'
  },

通过配置多个入口文件,则可以生成多个chunk,但是如果每个入口文件(chunk)之间存在重复的模块,则会导致被重复引用进各个模块中。我们可以通过使用 SplitChunksPlugin 插件来移除重复模块。

防止重复(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'
    }),

  ],

lazy Loading(懒加载)

懒加载可以帮助我们优化网页或应用程序提升加载速度。
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();

shim 预置依赖

在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'
  })
]

配置 typescript

//安装 webpack依赖

npm install --save-dev webpack webpack-cli
npm install --save-dev typescript ts-loader

tsconfig 配置

项目根目录新建tsconfig.json文件

{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "allowJs": true
  }
}

webpack 配置

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;

源码

杂记

webpack 配置es6语法

官方指南戳这里

//安装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 使用流程如下:

  1. 安装

npm install --save @babel/polyfill

  1. 在代码入口引入

import “@babel/polyfill”;
到这里,打包后的代码会被转化,但是babel-polyfill 里有所以规则导致打包后体积变很大,
如果我们只是想转换我们写的代码,则需要修改如下配置

options:{
  presets:[
    ['@babel/preset-env',{
    useBuiltIns:'usage'
    }]]
}

解决babel-polyfil 污染全局环境问题

使用 @babel/plugin-transform-runtime来进行转换

  1. 安装
    npm install --save-dev @babel/plugin-transform-runtime
    npm install --save @babel/runtime-corejs2
  2. .baberc
{
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "absoluteRuntime": false,
        "corejs": 2, //默认false  
        "helpers": true,
        "regenerator": true,
        "useESModules": false
      }
    ]
  ]
}

prefetch 与preload

两者都能提升code coverage,prefetch 是指将来某个节点需要加载的资源;preload 是指当前可能需要加载的资源

两者对比

  • preload会在父 chunk加载时,并行开始加载;prefetch 在父chunk加载完毕后开始加载
  • preload 具有优先级下载;而preload 是在浏览器空闲时开始加载
import(/* webpackPrefetch: true */ 'LoginModal');

import(/* webpackPreload: true */ 'ChartingLibrary');

欢迎大家关注我的前端仓库,这里有数据结构、常见面试题、框架、书籍等学习总结,有问题也可以在仓库 issues 或 emil: [email protected]

你可能感兴趣的:(tool,前端面试汇总)