webpack配置详细注释

刚看了官网的webpack例子,跟着做了一遍,把相关的配置用法注释了一遍,另外把我在配置中遇到的问题也分享出来。。。

一.webpack的配置详细注释

const config = {
    //入口文件配置
    entry:{
        mian:'./src/index.js',
        // print:'./src/print.js'
        vendor:['lodash']
    },
    //配置出口文件
    output:{
        //出口文件的名称
        filename:'[name].bundle.js',
        //出口文件的路径
        path:path.resolve(__dirname,'dist'),
        //publicPath 也会在服务器脚本用到,以确保文件资源能够在 http://localhost:3000 下正确访问
        publicPath:'/'
        
    },
    mode:'none',
    module:{
        //匹配除开js之外其他的文件,让相应的loader将文件解析成js文件
        rules:[
          {
              test:/\.css$/,
             //将 loaders 应用于最少数的必要模块中
              //使用 include 字段仅将 loader 模块应用在实际需要用其转换的位置中:
              include: path.resolve(__dirname, "src"),
              use:['style-loader','css-loader']
          },
          {
              test:/\.xml$/,
              use:'xml-loader'
          }
        ]
    },
    //追踪错误来源,若不配置,错误会在bundle.js中,不好找错误
    devtool:'inline-source-map',
    //配置插件,完成loader无法完成的功能
    plugins: [
       //离线任务未完成,报错:TypeError: WorkboxPlugin is not a constructor,原因待查
        // new WorkboxPlugin({
        //  // 这些选项帮助 ServiceWorkers 快速启用
        //  // 不允许遗留任何“旧的” ServiceWorkers
        //    clientsClaim: true,
        //    skipWaiting: true
        // }),
       //RuntimeChunkPlugin 的 'vendor' 实例,必须在 'common' 实例之前引入。
        new webpack.optimize.RuntimeChunkPlugin({
            name: "vendor"
        }),
        new webpack.optimize.RuntimeChunkPlugin({
            name: "common"
        }),
        /*
          自动生成html,及文件的引用
          html-webpack-plugin用来打包入口html文件
          entry配置的入口是js文件, webpack以js文件为入口, 遇到import, 用配置的loader加载引入文件
          但作为浏览器打开的入口html, 是引用入口js的文件, 它在整个编译过程的外面,
          所以, 我们需要html-webpack-plugin来打包作为入口的html文件
        */
        new HtmlWebpackPlugin({
        title: '柠檬🍋'
        }),
        //每次打包前会将dist文件夹中的文件清除,防止加载不必要的文件
        new CleanWebpackPlugin(['dist']),
        // webpack 内置的 HMR 插件
        new webpack.HotModuleReplacementPlugin(),
        //查看要修补(patch)的依赖
        new webpack.NamedModulesPlugin(),
        //删除未引用代码(dead code)的压缩工具(minifier)
        new UglifyJSPlugin(),
      //HashedModuleIdsPlugin,推荐用于生产环境构建:使用这个可以实现缓存,那些没有改变的文件就不会
        //随着每次构建而改变了,节约资源
        new webpack.HashedModuleIdsPlugin(),
    ],
    //webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载,devServer启动的就是webpack-dev-server
    //以下配置告知 webpack-dev-server,在 localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。
    devServer:{
        //告诉开发服务器(dev server),在哪里查找文件:
        contentBase:'./dist',
        port:'3333',
        //启动热重载
        hot:true 
    }
    
}
module.exports = config 

二.配置过程中遇到的问题

  • 1.error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.

查了资料发现,webpack 4.0.0-beta.0删除了 CommonsChunkPlugin,以支持两个新的选项(optimization.splitChunks 和 optimization.runtimeChunk)。

从webpack 4.0.0-beta.0 开始分割 Chunk 将不在使用 CommonsChunkPlugin 插件,而是使用 optimization 配置项,具体的实现原理可以参考 CommonsChunkPlugin。

对于那些需要细粒度控制缓存策略的人,可以通过 optimization.splitChunks和 optimization.runtimeChunk。 现在可以使用 module.rules[].resolve来配置解析。它与全局配置合并。

删掉 new webpack.optimize.CommonsChunkPlugin({
           name: 'common' // 指定公共 bundle 的名称。
       }),
改用  new webpack.optimize.RuntimeChunkPlugin({
           name: "common" // 指定公共 bundle 的名称
       }),

optimization的配置介绍如下:

//这里有两种使用方式:
const config= {
     //方式一:
     optimization:{...}
     //方式二:
     plugins: [
         new webpack.optimize.SplitChunksPlugin({...})
     ]
}

optimization参数介绍:

optimization: {
     runtimeChunk: {
        name: "manifest"        //指定公共 bundle 的名称
    },
    splitChunks: {
      chunks: "initial",         // 必须三选一: "initial" | "all"(默认就是all) | "async"
      minSize: 0,                // 最小尺寸,默认0
      minChunks: 1,              // 最小 chunk ,默认1
      maxAsyncRequests: 1,       // 最大异步请求数, 默认1
      maxInitialRequests: 1,    // 最大初始化请求书,默认1
      name: () => {},              // 名称,此选项可接收 function
      cacheGroups: {                 // 这里开始设置缓存的 chunks
        priority: "0",                // 缓存组优先级 false | object |
        vendor: {                   // key 为entry中定义的 入口名称
          chunks: "initial",        // 必须三选一: "initial" | "all" | "async"(默认就是异步)
          test: /react|lodash/,     // 正则规则验证,如果符合就提取 chunk
          name: "vendor",           // 要缓存的 分隔出来的 chunk 名称
          minSize: 0,
          minChunks: 1,
          enforce: true,
          maxAsyncRequests: 1,       // 最大异步请求数, 默认1
          maxInitialRequests: 1,    // 最大初始化请求书,默认1
          reuseExistingChunk: true   // 可设置是否重用该chunk(查看源码没有发现默认值)
        }
      }
    }
  },

2.filename: '[name].[chunkhash].js',
dev环境时候报错:Cannot use [chunkhash] or [contenthash] for chunk in '[name].[chunkhash].js' (use [hash] instead)
prod环境时候都可以用。
这里[chunkhash]与[hash]的区别:
chunkhash会给每个出口文件每次生成不一样的hash名字

Built at: 2018-4-13 16:34:23
                             Asset       Size  Chunks             Chunk Names
      main.3d547e36b08c284ce1a2.js   76.1 KiB       0  [emitted]  main
    vendor.3e5be7d4aebfd3b7d5dd.js   69.4 KiB       1  [emitted]  vendor
    common.38541d717f3e409861be.js   1.09 KiB       2  [emitted]  common

hash则每次给所有出口文件生成不一样的名字,但是所有出口文件的hash名字一样

Built at: 2018-4-13 16:33:22
                             Asset       Size  Chunks             Chunk Names
      main.5af0edc63954761b5bc3.js   76.1 KiB       0  [emitted]  main
    vendor.5af0edc63954761b5bc3.js   69.4 KiB       1  [emitted]  vendor
    common.5af0edc63954761b5bc3.js   1.09 KiB       2  [emitted]  common

bundle 的名称是它内容(通过 hash)的映射。如果我们不做修改,然后再次运行构建,我们以为文件名会保持不变。然而,如果我们真的运行,可能会发现情况并非如此:(译注:这里的意思是,如果不做修改,文件名可能会变,也可能不会。)

三.性能优化

避免在生产环境下才会用到的工具,也就是说不要在开发环境下用这些插件。
某些实用工具, plugins 和 loaders 都只能在构建生产环境时才有用。例如,在开发时使用 UglifyJsPlugin 来压缩和修改代码是没有意义的。以下这些工具在开发中通常被排除在外:

  • UglifyJsPlugin
  • ExtractTextPlugin
  • [hash]/[chunkhash]
  • AggressiveSplittingPlugin
  • AggressiveMergingPlugin
  • ModuleConcatenationPlugin

四.在构建项目时设置路径值

在开发模式中,我们通常有一个 assets/ 文件夹,它往往存放在和首页一个级别的目录下。这样是挺方便;但是如果在生产环境下,你想把这些静态文件统一使用CDN加载,那该怎么办?

想要解决这个问题,你可以使用有着悠久历史的环境变量。比如说,我们设置了一个名为 ASSET_PATH 的变量:

import webpack from 'webpack';

// 如果预先定义过环境变量,就将其赋值给`ASSET_PATH`变量,否则赋值为根目录
const ASSET_PATH = process.env.ASSET_PATH || '/';

export default {
  output: {
    publicPath: ASSET_PATH
  },

  plugins: [
    // 该插件帮助我们安心地使用环境变量
    new webpack.DefinePlugin({
      'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH)
    })
  ]
};

五. DefinePlugin的用法

DefinePlugin 允许创建一个在编译时可以配置的全局常量。这可能会对开发模式和发布模式的构建允许不同的行为非常有用。如果在开发构建中,而不在发布构建中执行日志记录,则可以使用全局常量来决定是否记录日志。这就是 DefinePlugin 的用处,设置它,就可以忘记开发和发布构建的规则。

new webpack.DefinePlugin({
  // Definitions...
})

用法

每个传进 DefinePlugin 的键值都是一个标志符或者多个用 . 连接起来的标志符。

  • 如果这个值是一个字符串,它会被当作一个代码片段来使用。
  • 如果这个值不是字符串,它会被转化为字符串(包括函数)。
  • 如果这个值是一个对象,它所有的 key 会被同样的方式定义。
  • 如果在一个 key 前面加了 typeof,它会被定义为 typeof 调用。

这些值会被内联进那些允许传一个代码压缩参数的代码中,从而减少冗余的条件判断。

new webpack.DefinePlugin({
  PRODUCTION: JSON.stringify(true),
  VERSION: JSON.stringify("5fa3b9"),
  BROWSER_SUPPORTS_HTML5: true,
  TWO: "1+1",
  "typeof window": JSON.stringify("object")
})

console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");

T> 注意,因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')

index.js

if (!PRODUCTION) {
  console.log('Debug info')
}

if (PRODUCTION) {
  console.log('Production log')
}

通过没有使用压缩的 webpack 的结果:

if (!true) {
  console.log('Debug info')
}
if (true) {
  console.log('Production log')
}

通过使用压缩的 webpack 的结果:

console.log('Production log')

功能标记(Feature Flags)

使用功能标记来「启用/禁用」「生产/开发」构建中的功能。

new webpack.DefinePlugin({
  'NICE_FEATURE': JSON.stringify(true),
  'EXPERIMENTAL_FEATURE': JSON.stringify(false)
})

W> When defining values for process prefer 'process.env.NODE_ENV': JSON.stringify('production') over process: { env: { NODE_ENV: JSON.stringify('production') } }. Using the latter will overwrite the process object which can break compatibility with some modules that expect other values on the process object to be defined.

服务 URL(Service URLs)

在「生产/开发」构建中使用不同的服务 URL(Service URLs):

new webpack.DefinePlugin({
  'SERVICE_URL': JSON.stringify("http://dev.example.com")
})

六.github地址

github地址😊

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