美文网首页vue
Webpack-基础概念

Webpack-基础概念

作者: IsaacHHH | 来源:发表于2018-10-27 11:48 被阅读7次

    深入浅出Webpack学习笔记

    基本概念

    常用的构建工具

    所有的构建工具所做的工做大致一样,都是把源代码翻译转换成可执行的代码,包括如下内容:

    • 代码转换:TypeScript转换成JavaScript,SCSS转换成CSS;
    • 文件优化:压缩JavaScript、CSS、图片等资源,利用一些优化手段,如摇树优化,移除无关代码;
    • 代码分割:提取多个页面的公共代码、提取首屏不需加载的代码让其异步加载,防止首次进入应用等待时间过长;
    • 模块合并:在一些模块化的项目中会有很多个模块和文件,需要构建工具把这些模块文件分类合并成一个文件;
    • 自动刷新:监听本地代码,自动构建加载,方便开发;
    • 代码校验:提交代码前进行代码规范检查;
    • 自动发布:更新完代码后,自动构建出线上代码,推送到线上或其他环境上;

    Npm Script

    Grunt

    Gulp

    Fis3

    Webpack

    https://www.webpackjs.com/
    Webpack是一个模块化打包工具,专注于构建模块化项目,在Webpack眼里一切文件都是模块,通过Loader转换翻译文件,通过Plugin注入钩子,最后输出由多个模块组合成的文件。

    之所以一切文件皆模块,如:JavaScript、CSS、SCSS以及图片等资源,在Webpack眼中都是模块,因为这样可以更好的理清描述各个模块之间的依赖关系,方便Webpack对模块进行打包组合,输出浏览器使用的静态资源。

    简单使用:

    module.exports = {
        // 定义入口文件
        entry: './index.js',
        // 定义打包输出文件
        output: {
            // 最终会把依赖的所有模块打包成一个bundle.js文件
            filename: './bundle.js'
        }
    }
    

    Webpack的优点

    • 专注于处理模块化项目,可以做到开箱即用,一步到位;
    • 通过Plugin进行扩展,完整好用又不失灵活;
    • 使用场景丰富,除了web端,其他场景也可以;
    • 社区活跃;
    • 开发体验好;

    缺点是只能采用模块化开发项目。

    Rollup

    安装与使用

    安装只需要一行命令,当然可以全局安装,但是不推荐。

    npm install -D webpack

    或者指定版本号:

    npm install -D webpack@2.xxx

    或者直接安装最新版:

    npm install -D webpack@beta

    注意:如果你使用的webpack版本较新,在webpack4.x测试下,你需要额外安装一依赖: npm i webpack-cli @webpack-cli/init。 可以参考webpack-cli

    运行Webpack命令:

    node_modules/.bin/webpack

    或者通过配置npm script来运行:

    "script": {
        "start": "webpack --config webpack.config.js"
    }
    

    具体如何使用?

    前面有了基本使用方法,但是具体落实到代码上该怎么写?我们可以通过构建一个采用CommonJs模块化的简单Demo来理解。

    建立如下文件:
    |-- index.html // 入口文件
    |-- show.js // js文件,里面我们随便写一个函数
    |-- main.js // 入口文件
    |-- package.json // npm 配置文件
    |-- webpack.config.js // webpack 配置文件

    index.html

    index.html文件内容包含了一个script和一个id等于app的div。

    <html>
        <head>
            <meta charset="utf-8"/>
        </head>
        <body>
            <div id="app"></div>
            <!-- 导入 Webpack 输出的 JavaScript 文件 -->
            <script src="./dist/bundle.js"></script>
        </body>
    </html>
    

    show.js

    show.js文件定义了一个show函数,该方法将给页面中的div插入一段文本;同时,我们利用CommonJs规范,将该函数导出。

    function show() {
        document.getElementById('app').innerText = 'hello world';
    }
    module.exports = show;
    

    main.js

    main.js文件将show.js引入,并执行show函数。

    const show = require('./show.js');
    show();
    

    webpack.config.js

    执行webpack构建执行命令的时候,会自动读取项目根目录下的webpack.config.js文件,所以我们新建该文件,并指明入口文件和打包输出文件。

    const path = require('path');
    module.exports = {
        entry: './main.js',
        output: {
            filename: './bundle.js',
            path: path.resolve(__dirnam, './dist') // 输出路径
        }
    }
    

    之所以使用CommonJs规范来导出webpack配置,是因为webpack运行在Node下,所以我们要使用CommonJs规范来描述一个如何构建的Object对象。

    执行webpack构建命令后,在项目根目录下会多出一个dist文件夹,以及一个bundle.js文件。bundle.js依赖main.jsshow.js两个文件以及内置的webpackBootstrap启动函数,从入口文件main.js出发,识别出源码中模块化导入的语句,把入口文件所依赖的模块或文件递归的打包到一个文件中:bundle.js文件。

    此时,直接打开index.html文件可以正常显示一段文案。

    使用Loader

    继续前面的内容,这次我们创建一个CSS文件: main.css
    建立如下文件:
    |-- index.html // 入口文件
    |-- show.js // js文件,里面我们随便写一个函数
    |-- main.js // 入口文件
    |-- package.json // npm 配置文件
    |-- webpack.config.js // webpack 配置文件
    |-- main.css

    文件中我们添加一段文本居中的样式:

    #app {
        text-align: center;
    }
    

    然后,我们在main.js引入这个CSS文件:

    // 引入css
    require('./main.css');
    
    const show = require('./show.js');
    show();
    

    编写工作做完后,我们自然的想到直接执行webpack构建命令,但是此时还不可以,因为Webpack原生仅支持解析JavaScript文件,如果需要
    解析其他类型的文件,需要引入相应的Loader,这里,我们因为需要解析CSS,所以需要引入CSS Loader。

    手动的去配置webpack.config.js文件:

    const path = require('path');
    module.exports = {
        entry: './main.js',
        output: {
            filename: './bundle.js',
            path: path.resolve(__dirname, './dist'),
        },
        module: {
            rules: [
                {
                    // 用正则匹配css文件
                    test: '/\.css$/',
                    use: ['style-loader', 'css-loader?minimize'], // minimize:需要进行压缩
                }
            ]
        }
    }
    

    上面我们简单的配置了一个Loader规则。

    Loader相当于一个翻译员,将某个文件源码翻译成可执行的代码。配置规则要求我们在rules数组中配置一个对象,指定test属性值来匹配那些文件需要翻译,通过use来指定需要使用哪些Loader,这里我们使用了style-loadercss-loader

    需要注意的是,在配置use属性的时候:

    • use属性值是一个数组,数组中的每个元素为loader的名字,尤其要注意的是,Loader的执行顺序是由后到前;
    • 可以给Loader以URL querystring的形式传递参数,比如前面的css-loader?minimize,具体参可以参考所使用的Loader文档;

    理解了Loader后,我们需要进行安装相应的Loader依赖:

    npm install -D style-loader css-loader

    所有准备工作做完后,我们执行构建命令:

    npm start 或者 node_modules/.bin/webpack

    然后再观察bundle.js文件,会发现代码更新了,并且CSS代码也被打包了进来,打开index.html,可以看到居中效果。

    这里我们提一下,CSS之所可以写在JavaScript中,归功于刚才引入的style-lader,大概远离就是将CSS样式以字符串的形式存储到JavaScript对象中,然后在网页执行的时候,通过DOM操作动态的加入到页面中的<style>标签中。

    当然,这样会导致页面加载时间变长,一定程度上需要我们再去优化处理,比如将CSS单独打包成一个文件,单独的输出,这种操作,我们可以通过Plugin来实现。Plugin也是Webpack的一个重要概念。

    Tips:

    use的配置中,给Loader传递参数除了刚才的写法,我们还可以传递一个对象来实现:

    module.exports = {
        rules: [
            {
                test: '/\.css$/',
                use: ['style-loader', { loader: 'css-loader', options: { minimize: true } }],
            }
        ]
    }
    

    除了在webpack.config.js中配置Loader外,还可以在代码文件中直接引入相关Loader,比如刚才的场景就可以这么处理:

    // main.js
    requrie('style-loader!css-loader?minimize!.main.css');
    

    这样就能指定对引入的main.css文件先进行css-loader在采用style-loder转换。

    另外,前面我们提到了Loader的记载顺序是从后到前的,所以这里我们必须把css-loader放在后面,也就是先执行。因为css-loder是将css代码编译,而style-loader是将编译好的css加到页面中。

    使用Plugin

    Plugin是用来扩展Webpack功能的,给Webpack带来了很大的灵活性,通过在构建流程中注入钩子来实现。

    继续前面的操作,我们这次需要优化一下,把main.css代码打包到单独的一个文件中。

    我们需要在配置文件webpack.config.js文件中添加plugins属性,来配置Plugin。

    const path = require('path');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
        entry: 'main.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, './dist'),
        },
        module: {
            rules: [
                {
                    test: '/\.css$/',
                    use: ExtractTextPlugin({
                        use: ['css-loader']
                    })
                }
            ]
        },
        plugins: [
            new ExtractTextPlugin({
                // 从.js中提取.css文件
                filename: `[name]_[contenthash:8].css`
            })
        ]
    }
    

    前面我们引入了新的插件,需要先安装:

    npm install -D extract-text-webpack-plugin

    然后我们执行构建命令,会发现dist目录下多出来一个.css结尾的CSS文件,bundle.js中也没有CSS代码了,然后我们手动将该CSS文件引入index.html就可以了。

    通过上面的代码我们可以看到,我们可以通过配置plugins属性来配置,其值是一个数组,数组中的每一项是一个实例,并且在实例化一个对象的时候,我们可以通过构造函数传入这个组件支持的属性配置。

    上面用到的extract-text-webpack-plugin就是一个插件,用来提取JavaScript中的CSS代码到一个单独的文件,filename属性指定了输出的文件名,[name]_[contenthash:8].cssname代表文件名,contenthash:8意思是根据文件内容算出8位hash值。

    该插件的其他配置可以在官网上找到。

    使用DevServer

    到目前为止,我们也只是做了打包构建的工作,在正常的开发过程中,还需要实现下面的功能:

    • 代码自动构建,自动刷新,实现文件变化监听;
    • 提供HTTP服务;
    • 支持Source Map,方便调试。

    上面提到的,Webpack原生支持1、3两点,对于提供HTTP服务,我们可以借助DevServe,是官方提供的一个开发工具。

    DevServer会自动开启一个本地HTTP服务,同时会自动启动Webpack构建,并通过WebSocket协议接受Webpack的文件的实时变更,做到可以实时预览,方便我们开发。

    安装与启动

    安装DevServer:

    npm install webpack-dev-server

    启动DevServer

    webpack-dev-server

    启动成功后,我们可以在控制台看到一串输出:

    Project is running at http://localhost:8080
    

    此时,我们访问http://localhost:8080就会自动执行根目录下的index.html文件。

    如果此时访问,我们会发现引入的bundle.js报404错误,是因为DevServer会把Webpack构建的文件保存在内存中,在要访问输出的文件时候,必须通过HTTP服务来访问,并且DevServer不会理会webpack.config.js配置里的output.path属性,所以我们需要访问http://localhost/bundle.js才可以。

    修改index.html文件js引用路径:

    <html>
        <head>
            <meta charset="utf-8"/>
        </head>
        <body>
            <div id="app"></div>
            <!-- 修改路径如下 -->
            <script src="./bundle.js"></script>
        </body>
    </html>
    

    实时预览

    我们现在修改main.jsmain.cssshow.js文件中的任一一处,保存后,浏览器便会自动刷新,加载修改后的代码。

    不过我们需要注意的是,通过DevServer启动的Webpack会自动开启文件监听,也就是这里的修改代码自动触发刷新页面的功能;而如果我们通过webpack来启动默认是不会开启监听模式的,只有我们显示的指明需要开启监听模式才可以。

    开启监听模式: webpack --watch

    DevServer会让Webpack在构建的过程中在JavaScript代码中注入一个代理客户端用于控制网页,并通过WebSocket协议进行通知,如果文件发生变化,会立刻告知刚才注入的代理客户端,代理客户端收到信息后,执行刷新网页操作。

    但是如果我们修改index.html文件不会触发网页刷新操作,这是因为Webpack在启动时候会以配置中心的entry为口入去递归解析entry所以来的文件,只有entry本身和其所依赖的文件才会被添加到监听对象中;另外,index.html文件脱离了JavaScript模块化系统,所以Webpack监听不到。

    模块热替换

    模块热替换不同于前面的页面刷新,这里的模块热替换,可以在不刷新页面的情况下实现重新加载新的模块代码的效果,当有新的模块代码时候,会将新的替换掉老的,并重新执行一遍代码,从而做到不刷新页面,却可以实时预览的效果。

    相比较来说,模块热更新在开发体验和效率上会略胜一筹。

    模块热替换默认是关闭的,我们可以在启动DevServer的时候带上--hot参数来开启。

    Source Map

    通过指定devtool source-map参数来开启Source Map功能。

    所谓的Source Map就是一份代码映射。在开过过程中,我们在浏览器看到的代码都是编译过的,所以没办法看到未编译的代码,很难去调试,代码可读性很差。

    而Source Map可以将编译前的代码给映射出来,让我们可以在源码上调试。Webpack支持生成Source Map,只需要在启动的时候带上--devtool source-map参数。然后启动后,我们便可以在Chrome开发者工具下调试。

    核心概念

    • Entry: 入口配置,Webpack构建的第一步将从Entry开始,可以抽象成输入;
    • Module:在Webpack里一切皆模块,一个模块对应一个文件。Webpack会从Entry入手,递归的找到所有的依赖模块;
    • Chunk:代码块,一个Chunk由多个模块组合而成,用于代码分割片段;
    • Loader:模块转换器,用于把模块中的内容按需求转换成新的内容,如ES6转换成ES5;
    • Plugin:扩展插件,在Webpack构建流程中特定时机注入扩展来改变逻辑和结果;
    • Output:输出结果,在Webpack经过前面一系列处理后返回的最终结果。

    Webpack启动后会从Entry配置的Module开始,递归的解析其依赖的所有Module,每找到一个Module,会调用相应的Loader对其进行转换,对Module转换后,在解析当前Module所依赖的Module,同样会调用相应的Loader。这些Module会以Entry为单位分组,一个Entry和其依赖的所有Module都会打包成一个Chunk。最终Webpack会把Chunk转换成文件输出,整个构建流程中,Webpack会在特定时机执行Plugin定义的逻辑。

    相关文章

      网友评论

        本文标题:Webpack-基础概念

        本文链接:https://www.haomeiwen.com/subject/sxfdtqtx.html