webpack入门

webpack是什么

官网:https://www.webpackjs.com/

一个现代JavaScript应用程序的静态模块打包器

默认:只对js进行处理,其他类型文件需要配置loader或者插件进行处理。
打包:将各个依赖文件进行梳理打包,形成一个JS依赖文件。

webpack产生的背景

为什么打包?
因为:
各个依赖文件的关系难以梳理,耦合程度较高,代码难以维护。
把所有依赖包都打包成为一个js文件(bundle.js)文件,会有效降低文件请求次数,一定程度提升性能。
逻辑多、文件多,项目复杂度提高

为什么要用webpack?

因为:

webpack除提供上述功能外,还充当了“翻译官”的角色,例如将ES6翻译为低版本的语法,将less、sass翻译为css等功能。
强大而灵活。

强大的插件(plugin)功能,webpack 自身也是构建于你在 webpack 配置中用到的相同的插件系统之上!

理解前端模块化

类似于一个公司由各个部门组成,一个工程也由各个模块组成,高内聚低耦合,各司其职。

作用域
定义:运行时变量、函数、对象可访问性
作用域决定了代码中变量和其他资源的可见性

全局作用域:

    var a = 1;
    window.a; // 1
    global.a; // 1
    

局部作用域:

    function a(){
        var v = 1;
    }
    window.v; // undefined

如果在传统js写法中,引入多个script,就很容易造成全局作用域冲突而导致不可预测的问题:

	<body>
		<script scr="./moduleA.js"></sciprt>
	  <script scr="./moduleB.js"></sciprt>
	  <script scr="./moduleC.js"></sciprt>
	</body>

改进步骤一,使用变量作用域形成局部作用域:

	// 定义模块内的局部作用域,以moduleA为例
	var Susan = {
		name: "susan",
	    sex: "female",
	    tell: function(){
	    	console.log("im susan")
	    }
	}

但是步骤一无法保证模块属性内部安全性,比如可能不小心改掉属性值,可以通过立即执行函数进行改写,形成闭包。
那么可以进行改进步骤二:
ps:
什么是立即执行函数?可以点击这里进行参考。
什么是自由变量?简单来说是跨作用域的变量,可以点击这里进行参考。(里面有一个句很好的知识点:创建这个函数的时候,这个函数的作用域就已经决定了,而是不是在调用的时候)

	// 定义模块内的闭包作用域(模块作用域),以moduleA为例
	var SusanModule = (function(){
	    var Susan = {
	    // 自由变量
		name: "susan",
	    // 自由变量
	    sex: "female",
	    // 只允许访问tell方法,不能访问和修改其他属性
	    return {
	    	tell: function(){
	    		console.log("im susan")
	    	}
	    }
	})()

对于步骤二还有一种写法,推荐使用这种写法,也是早期模块实现的方法:

// 定义模块内的闭包作用域(模块作用域),以moduleA为例
(function(window){
	var name = "susan"
    var sex = "female"
    functioon tell(){
    	console.log("im ", this.name)
    }
    window.susanModule = {tell}
})(window)// window作为参数传给

调用验证:

window.susanModule.tell(); //im susan

模块化的优点

  • 模块化的封装
  • 重用性
  • 解除耦合

模块化方案进化史

随着模块化优势体现,开发者更倾向于使用模块化协同开发项目,于是在发展过程中形成了很多规范:AMD、COMMONJS、ES6 MODULE

AMD

Asynchronous Module Definition(异步模块定义)
目前很少使用

	// 求和模块
	define("getSum", ["math"], funtion(math){
		return function (a,b){
	    	log("sum:"+ math.sum(a, b))
	    }
	})

COMMONJS

2009年出的规范,原本是为服务端的规范,后来nodejs采用commonjs模块化规范

// 通过require函数来引用
const math = require("./math");

// 通过exports将其导出
exports.getSum = function(a,b){
	return a + b;
}

ES6 MODULE

目前使用最多的便是这个

// 通过import函数来引用
import math from "./math";

// 通过export将其导出
export function sum(a, b){
	return a + b;
}

webpack的打包机制

根据import引入等关键字,将依赖文件打包成一个文件。

输出文件

输出文件的大体结构:

(function(module) {
	var installedModules = {};
    function __webpack_require__(moduleId){
    	// SOME CODE
    }
    // 。。。
    return __webpack_require__(0); // entry file
})([ /* modules array */])

上述结构中的核心方法:

function __webpack_require__(moduleId){
	// check if module is in cache
    if(installedModules[moduleId]){
    	return installedModules[moduleId].exports;
    }
    // create a new module (and put into cache)
    var module = installedModules[moduleId] = {
    	i: moduleId,
        l: false,
        exports: {}
    };
    // exe the module func
    modules[moduleId].call{
    	module.exports,
        module,
        module.exports,
        __webpack_require__
    };
    // flag the module as loaded
    module.l = true;
    // return the exxports of the module
    return module.exports;
}

webpack打包过程

  • 从入口文件开始,分析整个应用的依赖树
  • 将每个依赖模块包装起来,放到一个数组中等待调用
  • 实现模块加载的方法,并把它放到模块执行的环境中,确保模块间可以互相调用
  • 把执行入口文件的逻辑放在一个函数表达式中,并立即执行这个函数

npm install过程

  • 寻找报版本信息文件(package.json),依照它来进行安装

  • 查找package.json中的依赖,并检查项目中其他的版本信息文件

  • 如果发现了新包,就更新版本信息文件

webpack实战

基础准备

选择合适的目录,执行npm init -y 生成 package.json 文件

npm init -y

建议本地安装,安装依赖文件(更容易分别升级项目):

yarn add webpack webpack-cli -D

手动打包一个文件

创建文件 src/main.js

    class Student{
      getName(){
        return 'xiaoming'
      }
    }

手动单文件打包方式:

webpack ./src/main.js --mode development

loader

翻译官

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。

详细参见:https://www.webpackjs.com/concepts/#loader

plugins

loader的进一步扩展,可以执行的任务更为广泛

详细参见:https://www.webpackjs.com/concepts/#%E6%8F%92%E4%BB%B6-plugins-

scss支持

配置webpack.config.js

安装

yarn add css-loader  style-loader sass-loader  node-sass -D

配置文件修改如下:

  module:{
    rules: [{
      test: /\.scss$/,
      use: [{
          loader: "style-loader" // 将 JS 字符串生成为 style 节点
      }, {
          loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
      }, {
          loader: "sass-loader" // 将 Sass 编译成 CSS
      }]
    }]
  }

html-webpack-plugin

yarn add html-webpack-plugin -D

上面的配置,会把css以内联式的方式插入到head里面,如果需要提取样式,可以用 mini-css-extract-plugin

yarn add mini-css-extract-plugin -D

修改配置,如下:

plugins: [
    ...
    new miniExtractCss({
      filename:'common-[hash].css'
    })
  ],
  module: {
    rules: [{
      test: /\.scss$/,
      use: [
      // {
      //   loader: "style-loader" // 将 JS 字符串生成为 style 节点
      // },
      {
        loader: miniExtractCss.loader
      },
      {
        loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
      }, {
        loader: "sass-loader" // 将 Sass 编译成 CSS
      }]
    }]
  }

热更新支持

需要安装webpack-dev-server

yarn add webpack-dev-server -D

修改 webpack.config.js配置

//参考:https://webpack.docschina.org/configuration/dev-server/
  devServer: {
    //打开浏览器
    open: true
  },

修改 package.json

"scripts": {
   ...
    "dev": "webpack-dev-server --config ./webpack.config.js"
  },

图片转 base64

yarn add url-loader file-loader -D
 module: {
    rules: [
    ...
    {
          test: /\.(png|jpg|gif)$/,
          use: [
            {
              loader: 'url-loader',
              options: {
                limit: 81920
              }
            }
          ]
      }
    ...
    ]

完整的webpack.config.js

webpack.config.js 配置

const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  //开发模式:development,代码调试, 生产模式:production ,代码压缩,优化
  //如果mode不配置,会有警告提示信息
  mode: "development",
  //代码调试,可以看到源代码
  devtool: 'inline-source-map',
  //入口文件,如果不配置,默然找根目录下 /src/index.js
  // entry:"./src/js/index.js",
  entry: {
    'main': "./src/js/index.js",
    'detail': "./src/js/detai.js"
  },
  //打包完成,输出文件的位置(不能写相对路径),可以不配置,默认输出到dist目录
  output: {
    path: path.resolve(__dirname, './dev'),
    filename: '[name]-[hash].js'
  },
  devServer: {
    port: 9099,
    //打开浏览器
    open: true
  },
  plugins: [
    new htmlWebpackPlugin({
      title: 'webpack demo home',
      //模板文件路径
      template: "./src/views/index.html",
      //自动存储到output 配置的目录
      filename: 'index.html',
      chunks: ['main']
    }),

    new htmlWebpackPlugin({
      title: 'webpack demo home',
      //模板文件路径
      template: "./src/views/detail.html",
      //自动存储到output 配置的目录
      filename: 'detail.html',
      chunks: ['detail']
    }),
    new MiniCssExtractPlugin({
      //页面引用的样式文件名
      filename: '[name]-[hash].css',
      // chunkFilename: 'common.css',
    })
  ],
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/,
        //执行顺序:从右向左
        use: [
          // 将 JS 字符串生成为 style 节点
          'style-loader',
          // MiniCssExtractPlugin.loader,
          //将 CSS 转化成 CommonJS 模块
          'css-loader',
          //把.scss文件文件转换为.css文件
          'sass-loader'
        ]
      }
    ]
  }
}

babel配置

为了支持低版本的浏览器需要加入babel相关的配置:

yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/runtime -D
module:{
    rules:[
    ...
       {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime']
          }
        }
      }
    ...
    ]
}

@babel/plugin-transform-runtime
运行时引入 generators/async、babel-runtime/core-js(ES6->includes....)不会污染全局环境。

@babel/preset-env
转化最新语法如箭头函数, class, 扩展运算符,想要转换最新的api还需引入babel-polyfill(eg: includes)

@babel/polyfill
一些新的api:Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
ES6 在Array对象上新增了Array.from方法。

@babel-core
babel-core 的作用是把 js 代码分析成 ast ,方便各个插件分析语法进行相应的处理。

参考:
https://webpack.docschina.org/loaders/babel-loader/
https://www.babeljs.cn

posted on 2020-10-26 20:53  马克逊  阅读(109)  评论(0)    收藏  举报

导航