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

前言

少侠,愿你页底归来,已习得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",
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容