webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例

原理

我们创建的前端项目会用到大都会用到vue或react这些前端框架,这些项目在运行是需要构建的,因为像es6,less和sass,模板语法,vue指令和jsx语法是无法在浏览器中直接执行的,需要构建这样的一个操作来保证项目运行,webpack就是这样一个构建的工具。
webpack是一个打包模块化JavaScript的工具,在webpack里一切文件皆模块,通过Loader转换文件,通过 Plugin 注入钩子,最后输出多个模块组合成的文件。webpack专注于构建模块化的项目。
webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第1张图片上图为webpack在官网上的图片,一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。

在项目中webpack做的事情就是:分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用
webpack与node ,npm 的关系
webpack是npm生态中的一个模块,可以通过全局安装webpack来使用webpack对项目进行打包;webpack的运行依赖于node的环境,没有node是不能够打包的,但是webpack打包后的项目只是前端的静态资源和后台没有关系,也就是说不依赖于node,有后台能力的都可以部署项目;npm是于Node社区中产生的,是nodejs的官方包管理工具,当你下载安装好node的时候,npm cli 就自动安装好了。正是npm的包管理,使得项目可以模块化的开发,模块化开发大大提高了我们的开发效率,但是模块化开发的文件往往需要额外的处理才能让浏览器识别,手动处理非常繁琐,这就是webpack工具的意义。
目前最新的webpack版本是v4.43.0,安装最新版的webpack版本命令:

npm install --save-dev webpack

npm install 、npm install --save 和 npm install --save-dev 比较?

命令 描述
npm install X 模块安装到项目node_modules目录下;模块依赖不会写入devDependencies或dependencies 节点。如果删除node_modules目录,使用npm install 初始化项目时,运行 npm install 初始化项目时不会下载模块
npm install --save X(等价于npm install -S X) 模块安装到项目node_modules目录下;模块依赖被写进dependencies 节点;如果删除node_modules目录,使用npm install 初始化项目时,会将模块下载到项目目录(node_modules)下;运行npm install –production或者注明NODE_ENV变量值为production时,会自动下载模块到node_modules目录中;可以通过 require() 来引入本地安装的包。
npm install --save-dev X(等价于npm install -D X) 模块安装到项目node_modules目录下;模块依赖被写入devDependencies 节点。如果删除node_modules目录,使用npm install 初始化项目时,会将模块下载到项目目录(node_modules)下。运行npm install –production或者注明NODE_ENV变量值为production时,不会自动下载模块到node_modules目录中。可以通过 require() 来引入本地安装的包。
 "dependencies":应用程序在生产环境中需要的包,线上环境需要用到的依赖
 "devDependencies":应用程序开发测试需要的包,开发时依赖;//减少 node_modules目录的大小以及npm install花费的时间

webpack4.x和3.x比较大的区别

1、Node环境的升级:不再支持node4.0的版本,最低支持6.11.5。

2、增加了mode的配置,mode:‘production’ | ‘development’ | ‘none’,mode配置当前的开发环境,内置了很多功能,相比之前的版本减少了很多专门的配置。

development:开发环境,就是我们写代码的环境。

production:生产环境,代码放到线上的环境。

对mode不同的配置会启用不同的插件,直观的区别是开发环境的代码不提供压缩,生产环境的代码提供压缩。

3、原生支持处理JSON文件,不需要json-loader

4、webpack4之前,使用extract-text-webpack-plugin插件将css从js文件中分离出来打包,webpack4官方推荐使用 MiniCssExtractPlugin。

5、内置插件uglifyjs-webpack-plugin压缩js

6、CommonsChunkPlugin废弃,代替的是optimization.splitChunks 和 optimization.runtimeChunk

CLI:Command Line Interface(命令行接口)

为了更合适且方便地使用配置,可以在webpack.config.js中对webpack进行配置,CLI 中传入的任何参数会在配置文件中映射为对应的参数。

不使用配置文件时

webpack  [] -o //webpack 入口文件 -output bundled 文件
npm init
npm install --save-dev webpack webpack-cli//"webpack": "^4.43.0"

app/Greeter.js:定义一个返回包含问候信息的html元素的函数,并依据CommonJS规范导出这个函数为一个模块

module.exports = function() {
    var greet = document.createElement('div');
    greet.textContent = "Hi there and greetings!";
    return greet;
};

app/main.js:把Greeter模块返回的节点插入页面

const greeter = require('./Greeter.js');
document.querySelector("#root").appendChild(greeter());

public/index.html:最基础的html代码,它在这里目的在于引入打包后的js文件


  
    
    Webpack Sample Project
  
  
    

执行:

node_modules/.bin/webpack app/main.js --output public/bundle.js //非全局安装时

webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第2张图片
输出:Hi there and greetings!

使用webpack配置文件:配置文件也是简单的javascript模块,存放打包相关的信息。有了这个配置之后,再打包文件,只需在终端里运行webpack(非全局安装需使用node_modules/.bin/webpack)命令就可以了,这条命令会自动引用webpack.config.js文件中的配置选项。

module.exports = {
    entry:  __dirname + "/app/main.js",//唯一入口文件;“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
    output: {
      path: __dirname + "/public",//打包后的文件存放的地方
      filename: "bundle.js"//打包后输出文件的文件名
    }
}

webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第3张图片
核心概念:

  • Entry:
    Entry 用来指定webpack的打包入口,指示 Webpack 执行构建的第一步。可以在配置文件中配置 entry 属性,来指定一个或多个入口点。
    单入口:entry的值是一个字符串
module.exports = {
    entry:'./src/index.js'
}

多入口:entry的值是一个对象

module.exports = {
    entry:{
        index:'./src/index.js',
        search:'./src/search.js'
    }
}
  • Output:

指定webpack如何将编译后的文件输出到磁盘。

单入口基本的配置是:

1、filename :输出文件的文件名

2、path:输出文件的绝对路径

output没有多入口的说法,不管是单个入口还是多个入口都只有一个output,通过占位符来保证文件名称的唯一。

举个:

const path = require('path')
module.exports = {
    output:{
        path:path.join(__dirname,'dist'),
        filename:'[name].js'//占位符
    }
}

webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第4张图片

  • Loader:
    webpack开箱即用只支持js和json两种文件类型,当遇到其他格式的文件后,webpack并不知道如何去处理。此时,我们可以定义一种规则,告诉webpack当他遇到某种格式的文件后,去求助于相应的loader。通过使用不同的loader,webpack有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loader可以把React的中用到的JSX文件转换为JS文件。
    loader本身是一个函数,接收源文件通过loader函数转换,返回下一步使用的结果。
    Loader需要单独安装并且需要在webpack.config.js中的modules关键字下进行配置,Loader的配置包括以下几方面:
    1、test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
    2、loader:loader的名称(必须)
    3、include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
    4、query:为loaders提供额外的设置选项(可选)

  • Plugins:
    webpack之所以强大是因为它有丰富的插件系统,各种各样的插件几乎让 webpack 可以做任何构建相关的事情,任何loaders没有办法做的事情,都可以通过plugins来完成。
    这些插件能够按照我们配置的方式工作,完全依赖于tapable模块,它将这些插件注册为一个个钩子函数,然后按照插件注册时告知的方式,在合适的时机安排它们运行,最终完成整个打包任务。

  • Mode:
    是webpack4提出的新的概念,用来指定当前的构建环境是production、development还是none,设置mode的值可以去自动的触发webpack内置的函数,默认值是production。

  • Resolve
    Webpack 在启动后会从配置的入口模块出发找出所有依赖的模块,Resolve 配置 Webpack 如何寻找模块所对应的文件。

1、alias配置项通过别名来把原导入路径映射成一个新的导入路径,import Button from 'components/button 导入时,实际上被 alias 等价替换成了 import Button from ‘./src/components/button’ 。

resolve:{
  alias:{
    components: './src/components/'
  }
}

2、extensions在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在。
extensions: ['.js', '.json']//默认情况

3、modules配置 Webpack 去哪些目录下寻找第三方模块,默认是只会去 node_modules 目录下寻找。有时你的项目里会有一些模块会大量被其它模块依赖和导入,由于其它模块的位置分布不定,针对不同的文件都要去计算被导入模块文件的相对路径, 这个路径有时候会很长,就像这样 import ‘…/…/…/components/button’ 这时你可以利用 modules 配置项优化,假如那些被大量导入的模块都在 ./src/components 目录下,把 modules 配置成
modules:['./src/components','node_modules']

  • Performance
    某个打包后的包超过给定阈值时给出提示。
  • Devtool
    配置source-map的类型。
  • Externals
    externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法。externals中的配置,一般代表此引用来自外部library,不打包到bundle.js,而是在运行时获取这些外部依赖。
    其中属性名为模块名,属性值为变量名。
externals: {
    vue: 'Vue',
    vuex: 'Vuex',
    'vue-router': 'VueRouter'
}
  • DevServer
    配置热更新

实战使用

1、解析ES6

Babel是一个JavaScript编译器,可以将ECMAScript 2015+ 版本的代码转换为向后兼容的JavaScript语法,核心功能位于称为babel-core的包里,使用babel-loader解析ES6,babel-loader依赖babel,使用babel要先配置babel的配置文件.babelrc。

安装
npm i @babel/core @babel/preset-env babel-loader -D
.babelrc配置(Babel的配置文件,存放在项目的根目录里,用来设置转码规则和插件,两个配置项presets和plugins,presets定义转码规则)

{
    "presets": [
        "@babel/preset-env"
    ]
}

webpack.config.js配置

module.exports = {
    module:{
        rules:[
            {
                test: /.js$/,//匹配js文件
                use: 'babel-loader'//使用babel-loader解析
            }
        ]
    }
}

greet.js(ES6的语法)

export const greet = () => {
    let add = (a,b)=>{
        return a+b;
    }
    return add(5,5);
}

index.js(入口文件)

import {greet} from './greet'
document.write(greet());

webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第5张图片
2、解析JSX语法

Babel的babel-preset-react包可以转换React框架的JSX语法。
安装:npm i react react-dom @babel/preset-react -D
配置:
.babelrc文件的presets添加react的babel-preset-react包的配置"@babel/preset-react"
webpack.config.js

module.exports = {
    module:{
        rules:[
            {
                test: /.jsx$/,
                use: 'babel-loader'
            }
        ]
    },
    resolve: {
		extensions: ['.js', '.jsx']
}
}

组件ReactDemo.jsx:

import React, { Component } from 'react';
class ReactDemo extends Component {
    constructor(props) {
        super(props);
        this.state = { 
            list:['jsx语法','redux','react-router','reactHooks']
        }
    }
    render() { 
        return ( 
            

React课程目录

{ this.state.list.map((item,index)=>{ return
  • {item}
  • }) }
    ); } } export default ReactDemo;

    入口文件index.js

    import React from 'react'
    import {render} from 'react-dom'
    import ReactDemo from './ReactDemo'
    render(,document.getElementById('root'))
    

    3、CSS和Less

    webpack解析css需要css-loader和style-loader,css-loader用于加载.css文件,转换成commonJS对象,然后style-loader将样式通过/style>标签插入到head中,然后样式才会在代码中显示出来。
    安装npm i style-loader css-loader -D
    配置,loader的调用是链式调用,执行顺序是从右到左,先写style-loader,再写css-loader实际执行的时候是css-loader先解析css,再将解析好的css传递给style-loader。

    {
        test: /.css$/,
        use:[
          'style-loader',
          'css-loader'
        ]
    }
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第6张图片
    Less
    Less是CSS的预处理器,CSS预处理器为CSS增加一些编程的特性,无需考虑浏览器的兼容性问题,例如你可以在CSS中使用变量、简单的逻辑程序、函数等等在编程语言中的一些基本特性,可以让的CSS更加简洁、适应性更强、可读性更佳,更易于代码的维护等诸多好处。除了less之外,CSS的预处理器还有Sass(SCSS)、Stylus等。
    webpack使用less-loader解析less,less-loader将less转换成css。
    安装npm i less less-loader -D
    配置,在配置css解析的基础上添加less-loader。

    {
        test: /.less$/,
        use:[
          'style-loader',
          'css-loader',
          'less-loader'
        ]
    }
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第7张图片
    MiniCssExtractPlugin

    style-loader将样式通过 安装npm install --save-dev mini-css-extract-plugin
    配置

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module: {
            rules: [
                {
                    test: /\.(less|css)$/,
    
                    use: [
                        MiniCssExtractPlugin.loader,//与style-loader有功能上的互斥,要换成插件的loader
                        'css-loader',
                        'less-loader'
                    ]
                }
            ]
        }
    plugins: [
        new MiniCssExtractPlugin()
    ]
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第8张图片4、解析图片

    file-loader用于处理文件,可以解析图片。
    安装npm i file-loader -D
    配置

    {
        test:/.(png|jpg|gif|jpeg)$/,
        use: 'file-loader'
    }
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第9张图片
    如果页面中图片很多,会发出很多http请求,降低页面性能。这样可以使用url-loader解决。url-loader封装了file-loader,但不依赖于file-loader。url-loader提供了一个limit参数,小于limit字节的文件会被自动base64编码,大于limit字节的图片还会使用file-loader进行解析。
    安装npm install --save-dev url-loader
    配置

    {
      test:/.(png|jpg|gif|jpeg)$/,
      use: [
        {
          loader:'url-loader',
          options:{
          	limit: 10240//图片小于10k,webpack打包时会自动对图片做base64转换
          }
        }
        ]
    }
    

    组件引用两张图片,大小分别为17.6KB和6.34KB,使用file-loader构建时
    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第10张图片
    limit:10240
    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第11张图片
    limit:20480
    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第12张图片
    问:比较三种构建结果index.js的大小?
    base64的编码规则是3个普通字节可以由4个base64字符表示打包图片大小✖️4/3base原理解析
    5、Vue框架

    使用webpack来构建Vue的单文件组件
    安装依赖

    npm i -S vue
    npm i -D vue-loader vue-template-compiler
    
    • vue-loader:解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理。
    • vue-template-compiler:把 vue-loader 提取出的 HTML 模版编译成对应的可执行的 JavaScript 代码,这和 React 中的 JSX 语法被编译成 JavaScript 代码类似。预先编译好 HTML 模版相对于在浏览器中再去编译 HTML 模版的好处在于性能更好。
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    module.exports = {
    plugins: [
            new VueLoaderPlugin()
        ],
    module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: ['vue-loader'],
                },
            ]
        }
     }
    

    注:. 参考官方文档 https://vue-loader.vuejs.org/migrating.html#a-plugin-is-now-required. Vue-loader在15.*之后的版本需要伴生 VueLoaderPlugin来使用。
    例子:
    App.vue

    
    
    
    

    index.js

    import Vue from 'vue'
    import App from './App.vue'
    
    new Vue({
      el: '#root',
      render: h => h(App)
    });
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第13张图片
    6、webpack热更新
    webpack-dev-server基于nodejs构建,它是一个单独的组件,在webpack中配置之前需要单独安装作为项目依赖。代码有修改时自动构建,构建完成之后浏览器通过热更新的方式自动刷新修改后的结果,webpack-dev-server通常和HotModuleReplacementPlugin插件一起使用来开启热更新的功能。
    安装npm install --save-dev webpack-dev-server
    配置文件

    devServer: 
    {
        contentBase: "./public",//本地服务器所加载的页面所在的目录
        historyApiFallback: true,//不跳转
        inline: true//实时刷新
    } 
    

    开启本地服务器:package.json

    "server": "webpack-dev-server --open"//每次构建完成之后自动开启浏览器
    

    webpack解析ES6、jsx、css、图片字体、代码压缩、热更新使用示例_第14张图片
    7、HTML、CSS和JavaScript代码压缩
    开发完成后项目上线代码是需要经过压缩的,减少资源占用,提高访问速度。

    HTML文件压缩

    使用html-webpack-plugin插件,设置压缩参数。

    安装:npm i html-webpack-plugin -D

    const HtmlPlugin = require('html-webpack-plugin');
    plugins: [
       new HtmlPlugin({
           template: path.join(__dirname,'src/search.html'),//html文件模板所在位置
           filename:'search.html',//指定打包后的html文件名称
           chunks:['search'],//指定html使用的chunk
           inject:true,//true:打包后的js,css等会自动注入到html文件中
           minify:{
             html5:true,//根据html5规范解析输入
             collapseWhitespace:true,//折叠空白区域
             preserveLineBreaks:false,//当标记之间的空格包含换行符时,始终折叠为1换行符(不完全删除它)。必须与collapseWhitespace=true一起使用
             minifyCSS:true,//压缩文内css
             minifyJS:true,//压缩文内js
             removeComments:false//移除注释
        	}
        }),
    ]
    

    CSS文件压缩

    使用optimize-css-assets-webpack-plugin插件,同时使用cssnano处理器。

    安装npm install --save-dev optimize-css-assets-webpack-plugin cssnano

    const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
    plugins: [
        new OptimizeCSSAssetsPlugin({
        assetNameRegExp:/\.css$/g,
        cssProcessor:require('cssnano')
        })
    ]
    

    JS文件压缩
    webpack4内置了uglifyjs-webpack-plugin插件,默认打包后的js文件已经压缩。

    参考:
    http://www.ruanyifeng.com/blog/2016/01/babel.html

    https://segmentfault.com/a/1190000021881418

    https://blog.csdn.net/hjb2722404/article/details/89440492

    https://blog.csdn.net/CWH0908/article/details/90769823

    https://miss-me.github.io/2019/04/01/%E5%85%B3%E4%BA%8Enpm-install-save%E5%92%8Cnpm-install-save-dev%E7%9A%84%E6%80%BB%E7%BB%93/

    https://blog.csdn.net/pange1991/article/details/88591837

    https://www.jianshu.com/p/42e11515c10f

    你可能感兴趣的:(webpack)