美文网首页程序员
webpack教程_由浅入深的webpack配置

webpack教程_由浅入深的webpack配置

作者: 哔咖丘 | 来源:发表于2017-07-30 12:19 被阅读0次

    前言

    少侠,愿你页底归来,已习得webpack精要。

    那些你熟悉的概念

    那些你熟悉的概念

    入口起点

    • 字符串语法
    module.exports = {
        entry: './usage/index.js'
    }
    
    • 数组语法
      向 entry 属性传入「文件路径(file path)数组」将创建多个主入口
    module.exports = {
        entry: ['./plugins/hello.js','./usage/index.js']
    }
    

    问题:数组语法跟主入口文件引入依赖文件有什么区别?

    • 对象语法
    module.exports = {
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        }
    }
    

    输出

    const path = require('path');
    module.exports = {
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
     
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        }
    }
    

    说明:
    publicPath:声明资源对外链接,如上配置可以通过<script src="/js/usage.index.js">去访问你的js资源。

    加载器(Loaders)

    loader是对应用程序中的资源进行转换。他们是函数,可以将文件资源作为参数来源,经过一番处理后返回性的文件资源。类似于fis3或者gulp中的插件

    • 通过webpack.config.js配置
    const path = require('path');
    module.exports = {
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
      
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        },
        rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader?modules',
            ]
        }]
    }
    
    • 通过require或CLI
    require('style-loader!css-loader?modules!./styles.css');
     
    webpack --module-bind jade --module-bind 'css=style!css'
    

    说明:webpack通过「!」区分加载器。

    • 加载器是如何解析的?
      loader遵循标准的模块解析,多数情况下,从模块路径解析(通常将模块路径认为是npm install 的node_module路径)。

    插件

    插件是webpack的支柱功能,它的目标在于解决loader无法实现的其他事。webpack插件是一个具有apply 属性的javascript对象。

    • 使用配置
    const path = require('path');
    module.exports = {
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
      
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        },
        rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader?modules',
            ]
        }],
         
        plugins: [
            new ManifestPlugin({
                fileName: 'manifest.json',
                basePath: './build/',
                seed: {
                    name: 'My Manifest'
                }
            })
        ]
    }
    

    说明:这里使用的是一个缓存插件,具体的作用我们后续讲解。

    那些我模糊的名词

    那些我模糊的名词

    模块

    • 模块的解析规则
      模块的解析原理是将路径转化为最终的绝对路径,然后根据这个路径找到相应模块。
      绝对路径:
      import "/home/me/file";
      import "C:\\Users\\me\\file";
      
      相对路径:
      import "../src/file1";
      import "./file2";
      
      说明:在这种情况下,出现 import 或 require 的资源文件的目录被认为是上下文目录。
      模块路径:
       import "module";
       import "module/lib/file";
      
      设置为模块路径时,模块将在 resolve.modules 中指定的所有目录内搜索。也通过 resolve.alias 配置为模块路径创建别名,eg:
       const path = require('path');
       module.exports = {
         entry: {
           "usage.index": './usage/index.js',
           "usage.main": './usage/main.js'
          },
          output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
          },
          rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader?modules',
            ]
          }],
          plugins: [
            new ManifestPlugin({
                fileName: 'manifest.json',
                basePath: './build/',
                seed: {
                    name: 'My Manifest'
                }
            })
          ],
          resolve: {
            alias: {
              "jquery": path.resolve(__dirname, 'src/js/libs/jquery-1.11.1.min.js')
            }
          }
      }
      

    依赖图表

    从入口点开始,webpack 递归地构建一个依赖图表,这个依赖图表包括你应用所需的每个模块,然后将所有模块打包为少量的包(bundle) - 通常只有一个包 - 可由浏览器加载。

    构建目标

    因为服务端可浏览器端代码都可以用JavaScript编写,因此,webpack提供了 nodeweb 两种类型的构建,我们可以通过设置构建目标实现不同类型的构建。

    • 如何配置?
    const path = require('path');
    module.exports = {
        target: 'node',  // 默认是web,可以省略
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
      
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        }
        // ...
    }
    

    通过 module.exports = [clientConfig, serviceConfig],的方式实现多target配置。

    • 模块热替换(HMR)
      模块热替换功能会在应用程序运行过程替换、添加或删除模块。这使得你可以在独立模块变更后,无需刷新浏览器页面,就可以更新这些模块,极大地提高开发效率。
    • 如何配置?
    const path = require('path');
    const webpack = require('webpack');
     
    module.exports = {
        target: 'node',  // 默认是web,可以省略
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
      
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        },
         
        plugins: [
            // 开启全局的模块热替换(HMR)
            new webpack.HotModuleReplacementPlugin(),
            // 当模块热替换(HMR)时在浏览器控制台输出对用户更友好的模块名字信息
            new webpack.NamedModulesPlugin(),
        ],
     
        rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader?modules',
            ]
        }],
        // ...
    }
    

    你的入口index.js:

    import _ from 'lodash';
    import styles from './css/main.css';
    function component () {
        let element = document.createElement('div');
        element.innerHTML = _.join(['hello', 'webpack'],' ');
        return element;
    }
    document.body.appendChild(component());
    

    说明:在该配置下,修改 mian.css 样式表后,不需要刷新浏览器页面即可看到更新。
    问题:在入口index.js文件中引入样式表,那么最终样式表会跟js文件一起打包,如此会影响到页面的加载性能。那么要如何分离呢?
    Answer: 使用 extract-text-webpack-plugin 解决你的问题。

    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
      // ...
      plugins: [
        new ExtractTextPlugin('dist/style.css')  // 不支持热替换
      ],
      module: {
        rules: [{
          test: /\.css$/,
          use: ExtractTextPlugin.extract({
            use: 'css-loader'
          })
        }]
    }
    

    说明:该插件作用之后,会将入口文件中引用的 main.css 构建成 dist/style.css 。另,该插件不支持热替换,亦即在本地开发过程,使用热替换达到独立模块热替换,在build过程开启开插件做分离构建。

    那些我们遇到的问题

    那些我们遇到的问题

    如何做精准的构建

    const path = require('path');
    module.exports = {
        entry: {
            "usage.index": './usage/index.js',
            "usage.main": './usage/main.js'
        },
      
        output: {
            filename: '[name].[chunkhash].js',  // 每一个文件拥有自己唯一的hash值,不要在开发环境下使用,这会增加编译时间,不能与HMR插件共同使用
            path: path.resolve(__dirname, 'usage/dist/js'),
            publicPath: '/js/'
        }
    }
    

    说明:在该配置下,只会对有作更改的入口文件进行构建。区分:filename: '[name].[hash].js',这种配置下,所有的入口文件共享一个hash值,即其中某个入口文件更改之后,会对所有的入口文件做更改。
    问题:重复构建导致许多的垃圾文件?文件名每次变更,html引入麻烦?这些....,交给webpack插件,都不是问题!

    plugins: [
        new ManifestPlugin({
            fileName: 'manifest.json',
            basePath: './build/',
            seed: {
                name: 'My Manifest'
            }
        })
    ]
    

    使用了插件,会生成一个映射文件,从这里,可以取到对应的文件名:

    缓存文件映射表

    webpack js资源断点调试技巧

    • 调试类型:

      • source-map:可断点调试,可在生产环境使用
      • cheap-module-source-map:可断点调试,可在生产环境使用
      • eval-source-map:能看源码,不可断点调试,不可在生产环境使用

      这里只是列出部分常用的类型,具体可参考webpack文档。

    • 如何配置?

    module.exports = {
        devtool: 'source-map',// 可断点调试
    }
    
    • 开始调试
      webpack断点调试
    • 如何分离开发和生产环境的配置?
      • 设置你的webpack.config.js
      function buildConfig(env) {
        return require('./config/' + env + '.js')({ env: env })
      }
      module.exports = buildConfig(env);
      
      • 设置你的package.json
      "build:dev": "webpack --env=dev --progress --profile --colors",
      "build:dist": "webpack --env=prod --progress --profile --colors",
      

    相关文章

      网友评论

        本文标题:webpack教程_由浅入深的webpack配置

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