webpack 完整案例 配置别名_webpack 配置别名 - CSDN
精华内容
参与话题
  • webpack配置学习-上

    2020-08-18 10:46:02
    待补充

    配置

    webpack是需要传入一个配置对象的,可以通过两种方式:终端或者Node.js来指定配置选项。

    注意:配置中使用Node内置的path模块,并在前面加上全局变量__dirname,可以防止不同操作系统之间的文件路径问题,并且可以使相对路径按照预期工作

    配置方式

    导出为一个函数

    作为导出一个配置对象的替代,可以从webpack配置文件中导出一个函数,该函数在调用事,可传入两个参数:环境对象(environment)作为第一个参数,语法案例可以查看CLI文档的环境选项;map对象(argv)作为第二个参数,这个对象描述了传递给webpack的选项,并且具有output-filename和optimize-minimize等key;
    示例:

    module.exports=function(env,argv) {
    	return {
    		mode:env.production?'production':'development',
    		devtool:env.production?'source-maps':'eval',
    		plugins:[
    			new webpack.optimize.UglifyJsPlugin({
    				compress:argv['optimize-minimize']
    			})
    		]	
    	}
    }
    

    导出一个promise

    webpack将运行由配置文件导出的函数,并且等待Promise返回。便于需要异步地加载所需的配置变量

    module.exports=()=>{
    	return new Promise((resolve,reject)=>{
    		setTimeout(()=>{
    			resolve({
    				entry:'./app.js'
    			})
    		},5000)
    	})
    }
    

    导出多个配置对象

    module.exports = [{
      output: {
        filename: './dist-amd.js',
        libraryTarget: 'amd'
      },
      entry: './app.js',
      mode: 'production',
    }, {
      output: {
        filename: './dist-commonjs.js',
        libraryTarget: 'commonjs'
      },
      entry: './app.js',
      mode: 'production',
    }]
    
    

    入口和上下文

    entry对象用于webpack查找启动并构建bundle,上下文context是入口文件所处的目录的绝对路径的字符串。

    context

    类型:string
    基础目录,绝对路径,用于从配置中解析入口起点(entry point)和loader

    	context:path.resolve(__dirname,'app')
    

    默认使用当前目录,但是推荐在配置中传递一个值,便于配置独立于当前执行路径

    entry

    类型:string | [string] | object { <key>: string | [string] } | (function: () => string | [string] | object { <key>: string | [string] })

    起点是应用程序的起点入口。从这个起点开始,应用程序启动执行。如果传递一个数组,那么数组的每一项都会执行。

    注意:动态加载的模块不能作为入口起点。
    简单规则:每个HTML页面都有一个入口起点。单页应用(SPA):一个入口起点,多页应用(MPA):多个入口起点。

    entry : {
    	home:'./home.js',
    	about:'./about.js',
    	contact:'./contact.js'
    }
    

    命名

    如果传入一个字符串或字符串数组,chunk会被命名为main。如果传入一个对象,则每个键(key)会是chunk的名称,该值描述了chunk的入口起点。

    动态入口

    entry: () => './demo'
    

    或者

    entry:() => new Promise (resolve) => resolve(['./demo','./demo2']);
    

    注意:当结合output.library选项时,如果传入数组,则只导出最后一项。

    输出(output)

    output位于对象最顶级键(key),包括了一组选项,指示了webpack如何去输出、以及在哪里输出(bundle、asset和其他所打包或使用webpack载入的任何内容)

    output.auxiliaryComment

    类型:string || Object
    output.library、output.libraryTarget一起使用时,此选项允许用户向导出容器(export wrapper)中插入注释。如果要为libraryTarget每种类型都插入相同的注释,可以将auxiliaryComment设置为字符串

    output:{
      library: "someLibName",
      libraryTarget: "umd",
      filename: "someLibName.js",
      auxiliaryComment: "Test Comment"
    }
    

    如果想要给libraryTarget每种类型的注释进行更细粒度的控制,可以传入一个对象

    auxiliaryComment: {
      root: "Root Comment",
      commonjs: "CommonJS Comment",
      commonjs2: "CommonJS2 Comment",
      amd: "AMD Comment"
    }
    

    output.chunkFilename

    类型:string || function
    此选项决定了非入口(no-entry)chunk文件的名称。可取值,请查看output.filename选项。

    注意:这些文件名需要在runtime根据chunk发送的请求去生成。因此需要在webpack runtime 输出bundle值时,将chunk id 的值对应映射到占位符(如[name] 和 [chunkhash])。但是这会增加文件大小,并且在任何chunk的占位符值修改后,都会使bundle失效。

    默认使用 [id].js或从output.filename中推断出的值([name]会被预先替换为[id][id].

    output.chunkLoadTimeout

    类型:integer
    chunk请求到期之前的毫秒数,默认为120000.
    注意:webpack2.6.0以上支持此选项

    output.crossOriginLoading

    类型:boolean string
    只用于target是web,使用了通过script标签的JSONP来按需加载chunk
    启用cross-origin属性加载chunk。以下是可接手的值:

    crossOriginLoading:false //禁用跨域加载(默认)
    crossOriginLoading:'anonymous'//不带凭据启用跨域加载
    crossOriginLoading:'use-credentials'//带凭据启用跨域加载
    

    output.jsonpScriptType

    类型:string
    允许自定义script的类型,webpack会将script标签注入到DOM中以下载异步chunk。可以使用以下选项:

    • “text/javascript”(默认)
    • “module”:与ES6就绪代码一起使用

    output.devtoolModuleFilenameTemplate

    类型:string | function(info)
    此选项仅在devtool使用了需要模块名称的选项时使用
    自定义每个source map的sources数组中使用的名称。可以通过传递模块字符串或者函数来完成。
    例如,当使用devtool:‘eval’,默认值是:

    devtoolModuleFilenameTemplate:'webpack://[namespace]/[resource-path]?[loaders]'
    

    模板字符串列表

    模板 描述
    [absolute-resource-path] 绝对路径文件名
    [all-loaders] 自动和显示的loader,并且参数取决于第一个loader名称
    [hash] 模块标识符的hash
    [id] 模块标识符
    [loaders] 显式的loader,并且参数取决于第一个loader名称
    [resource] 用于解析文件的路径和用于第一个loader的任意查询参数
    [resource-path] 不带任何查询参数,用于解析文件的路径
    [namespace] 模板命名空间。在构建成为一个library之后,通常也是library名称,否则为空

    当使用一个函数,同样的选项要通过info参数并使用驼峰式

    devtollModuleFilenameTemplate:info => {
    	return `webpack:///${info.resourcePath}?${info.loaders}`
    }
    

    output.devtoolFallbackModuleFilenameTemplate

    类型:string | function(info)
    当上面的模板字符串或函数产生重复时使用的备用内容

    output.devtoolNamespace

    类型:string
    此选项确定了output.devtoolModuleFilenameTemplate使用的模块名称空间。未指定时的默认值为:output.library。在加载多个通过webpack构建的library时,用于防止sourcemap中源文件路径冲突。

    output.filename

    类型:string | function
    此选项决定了每个输出bundle的名称,这些bundle将写入到output.path选项指定的目录下
    对于单个入口起点,filename会是一个静态名称

    filename:"bundle.js"
    

    当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个bundle,应该使用以下一种替换方式,来赋予每个bundle一个唯一的名称

    • 使用入口名称
    filename:"[name].bundle.js"
    
    • 使用内部chunk.id
    filename:"[id].bundle.js"
    
    • 使用每次构建过程中,唯一的hash生成
    filename:"[name].[hash].bundle.js"
    
    • 使用基于每个chunk内容的hash
    filename:"[chunkhash].bundle.js"
    

    注意:

    • 此选项被称为文件名,但是还是可以使用像’js/[name]/bundle.js’这样的文件夹结构
    • 此选项不会影响按需加载chunk的输出文件。

    模板字符串的值:

    模板 描述
    [hash] 模块标识符(module identifier)的hash
    [chunkhash] chunk内容的hash
    [name] 模块名称
    [id] 模块标识符(module identifier)
    [query] 模块的query,例如,文件名?后面的字符串

    [hash]和[chunkhash]的长度可以使用[hash:16] (默认为20)来指定。或者通过指定output.hashDidestLength在全局配置长度

    如果将这个选项设为一个函数,函数将返回一个包含上面表格中替换信息的对象

    output.hashDigest

    在生成hash时使用的编码方式,默认为‘hex’。支持Node.js hash.digest的所有编码

    output.hashDigestLength

    散列摘要的前缀长度,默认为20

    output.hashFunction

    类型:string | function
    散列算法,默认为’md5’。支持Node.JS ctypto.createHash的所有功能。从4.0.0-alpha2开始,hashFunction 可以返回自定义hash的构造函数。可以提供一个不加密的哈希函数(优化性能)

    hashFunction:require('metrohash').MetroHash64
    

    确保hash函数有可访问的update和digest方法

    output.hashSalt

    可选的加盐值,通过Node.JS hash.update来更新哈希

    output.hotUpdateChunkFilename

    类型:string | function
    自定义热更新chunk的文件名。可选值参考output.filename选项
    占位符只能是[id] 和 [hash],默认值是:

    hotUpdateChunkFilename:"[id].[hash].hot-update.js"
    

    output.hotUpdateFunction

    类型:function
    只在target是web时使用,用于加载热更新(hot update)的JSONP函数
    JSONP函数用于异步加载(async load)热更新(hot-update)chunk

    output.hotUpdateMainFilename

    类型:string | function
    自定义热更新的主文件名。可选值参考output.filename选项
    占位符只能是[hash] ,默认值是

    hotUpdateMainFilename:"[hash].hot-update.json"
    

    output.jsonpFunction

    类型:string
    只在target是web时使用,用于按需加载chunk的JSONP函数
    JSONP函数用于异步加载chunk,或者拼接多个初始chunk
    如果在同一网页中使用了多个webpack runtime,则需要修改此选项
    如果使用了output.library选项,library名称是自动追加的

    output.library

    类型:string | object (webpack3.1.0开始,用于libraryTarget:‘umd’)
    output.library的值的作用,取决于output.libraryTarget选项的值;
    注意:output.libraryTarget的默认选项是var
    所有如果使用以下配置选项:

    output:{
    	library:'Mylibrary'
    }
    

    如果生成的输出文件,是在HTML页面中作为一个script标签引入,则变量MyLibray将与入口文件的返回值绑定。

    output.libraryTarget

    类型:string
    默认值:var
    用于配置如何暴露library。
    注意:此选项与分配给output.library的值一同使用。
    常用选项:

    1. 暴露为一个变量
    libraryTraget:'var' // (默认值) 当library加载完成,入口起点的返回值将分配给一个变量
    //当使用此选项时,将output.library设置为空,会因为没有变量导致无法赋值
    
    libraryTarget:'assign' //产生一个隐含的全局变量,可能会潜在的重新分配到全局中已存在的值(谨慎使用)
    //如果变量名没有在作用域中进行定义,则library将会被设置在全局作用域内
    //当使用此项时,将output.library设置为空,将产生一个破损的输出bundle
    
    1. 通过在对象上赋值暴露
      下列选项将入口起点的返回值赋值给一个特定对象的属性下。如果output.library未赋值为一个非空字符串,则默认行为是,将入口起点返回的所有属性都赋值给一个对象(此对象由output.libraryTarget特定)
      注意:不设置output.library将导致由入口起点返回的所有属性,都会被赋值给给定的对象;但是并不会检查现有的属性名是否存在
    libraryTarget:'this'
    //入口起点的返回值将分配给this的一个属性(此名称由output.library定义)下
    
    libraryTarget:'window'
    //入口起点的返回值将使用output.library中定义的值
    //分配给window对象的这个属性下
    
    libraryTarget:'global'
    //入口起点的返回值将使用output.library中定义的值
    //分配给global对象的这个属性下
    
    libraryTarget:'commonjs'
    //入口起点的返回值将使用output.library中定义的值,
    //分配给exports对象,这个名称意味着,模块用于CommonJS环境
    
    1. 模块定义系统
      以下选项将导致bundle带有更完整的模块头部,以确保与各种模块系统的兼容性,根据output.libraryTarget选项不同,output.librart选项将具有不同的含义
    libraryTarget:'commonjs2'
    //入口起点的返回值将分配给module.exports对象。这个名称意味着模块用于CommonJS环境
    //注意:output.library会被省略,因此对于此特定的output.libraryTarget,无需再设置output.library
    
    libraryTarget:'amd'
    //将library暴露为AMD模块
    //AMD模块要求入口chunk通过特定的属性定义
    //否则,直接加载生成的AMD bundle将导致报错
    
    libraryTarget:'umd'
    //将library暴露为所有的模块定义下都可以运行的方式
    //注意:省略library会导致将入口起点返回的所有属性,直接赋值给root对象
    

    注意:从webpack3.1.0开始,可以将library指定为一个对象,用于给每个target起不同的名称

    1. 其他Targets
    libraryTarget:'jsonp'//将入口起点的返回值,包裹到一个jsonp包装容器中
    

    output.path

    类型:string
    output目录对应一个绝对路径

    path:path.resolve(__dirname,'dist/assets')
    

    output.pathinfo

    类型:boolean
    告诉webpack在bundle中引入所包含模块信息的相关注释。此选项默认值是false,并且不应该用于生产环境。
    注意:这些注释也会被添加至经过tree shaking 后生成的bundle中

    output.publicPath

    类型:string | function

    该选项指定了在浏览器中引用的该输出目录对应的公开URL。
    对于按需加载或加载外部资源时,output.publickPath十分重要
    该选项是以runtime(运行时)或loader(载入时)所创建的每个URL为前缀。因此在多数情况下该选项会以/结束

    默认值是一个空字符串""

    在编译是无法知道输出文件的publicPath的情况下,可以留空,然后在入口文件处使用自由变量__webpack_public_path_,以便在运行时进行动态设置

    output.sourceMapFilename

    类型:string
    此选项会向硬盘写入一个输出文件,只在devtool启用了SourceMap选项时才使用。
    配置source map 的命名方式。默认使用"[file].map"
    可以使用#output-filename中[name],[id],[hash]和[chunkhash]替换符号。除此之外,还可以使用以下替换符号。[file]占位符会被替换为原始文件的文件名。
    建议只使用[file]占位符,因为其他占位符在非chunk文件生成的SourceMap时不起作用

    模板 描述
    [file] 模块文件名称
    [filebase] [模块basename]

    output.sourcePrefix

    类型:string
    修改输出bundle中每行的前缀

    sourcePrefix:'\t'
    

    注意:默认情况下使用空字符串。使用一些缩进会看起来美观,但是可能导致多种字符串中的问题

    output.strictModuleExceptionHandling

    类型:boolean
    如果一个模块是在require时抛出异常,告诉webpack从模块实例缓存(require.cache)中删除这个模块。
    处于性能原因,默认为false。
    当设置为false时,该模块不会从缓存中删除,这将造成仅在第一次require调用时抛出异常(会导致与node.js不兼容)。

    output.umdNamedDefine

    类型:boolean
    当使用了libraryTarget:‘umd’,设置:

    umdNamedDefine:true
    

    会对UMD的构建过程中的AMD模块进行命名。否则就使用匿名的define

    模块

    这些选项决定了如何处理项目中的不同类型的模块

    module.noParse

    RegExp | [RegExp] | function (从webpack3.0.0开始)

    防止webpack解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有import、require、define的调用,或任何其他导入机制。忽略大型的library可以提高构建性能

    noParse:/jquery|lodash/
    
    //从webpack3.0.0开始
    noParse:function(content) {
    	return /jquery|lodash/.test(content)
    }
    

    module.rules

    类型:array
    创建模块时,匹配请求的规则数组。这些规则能够修改模块的创建方式。这些规则能够对模块(module)应用loader,或者修改解析器(parser)

    Rule

    每个规则可以分为三个部分-条件(condition),结果(result)和嵌套规则(nested rule)

    条件

    条件有两种输入值:

    1. resource:请求文件的绝对路径。已经根据resolve规则解析
    2. issuer:被请求资源的模块文件的绝对路径。是导入时的位置
      在规则中,属性test,inculde,exclude和resource对resource匹配,并且属性issuer对issuer匹配
      当使用多个条件时,所有条件都匹配
    结果

    规则结果只在规则条件匹配时使用。
    规则有两种输入值:

    1. 应用的loader:应用唉resource上的loader数组
    2. Parser选项:用于为模块创建解析器的选项对象
    嵌套

    可以使用属性rules和oneOf指定嵌套规则
    这些规则用于在规则条件匹配时进行取值

    Rule.enforce

    用于指定loader种类,没有值表示是普通通loader
    选项值:‘pre’(优先处理) | ‘post’(最后处理)

    还有一个额外的种类行内loader,loader被应用在import/require行内

    行内loader

    语法介绍:
    在import语句或任何等同于import语法中指定loader,使用!将资源中的loader分开。每个部分都会相当于当前目录解析

    import Styles from 'style-loader!css-loader?modules!./styles.css';
    

    所有loader通过前置、行内、普通、后置的顺序使用

    //所有普通loader可以通过在请求中加上!前缀来忽略(覆盖)配置中的loader
    require('!inline-loader!./a.js')
    //所有普通和前置 loader 可以通过在请求中加上 -! 前缀来忽略(覆盖)。
    require('-!inline-loader!./a.js')
    //所有普通,后置和前置 loader 可以通过在请求中加上 !! 前缀来忽略(覆盖)。
    require('!!inline-loader!./a.js')
    

    注意:不应该使用行内loader和!前缀,因为它们是非标准的。

    Rule.exclude和Rule.include

    Rule.exclude和Rule.include是Rule.resource.exclude和Rule.resource.include的简写。如果使用了上述两个选项,则不能使用Rule.resource

    Rule.issuer

    一个条件,用于与被发布的request对应的模块项匹配。
    这个选项可以用来将loader应用到一个特定模块或一组模块的依赖中

    Rule.loader

    Rule.loader是Rule.user:[{loader}]的简写

    Rule.oneOf

    规则数组,当规则匹配时,只使用第一个匹配规则

    {
    	test:/.css$/
    	oneOf:[
    		{
    			resourceQuery:/inline/,//foo.css?inline
    			use:'url-loader'
    		},
    		{
    			resourceQuery:/external/,//foo.css?external
    			use:"file-loader"
    		}
    	]
    }
    
    Rule.options/Rule.query

    Rule.options和Rule.query是Rule.use:[{options}]的简写

    Rule.parser

    解析选项对象,所有应该的解析选项都将合并
    解析器(parser)可以查阅这些选项,并相应的禁用或重新配置。大多数默认插件,配置值如下:

    • 将选项设置为false,将禁用解析器
    • 将选项设置为true,或不修改将其保留为undefined,可以启用解析器

    一些解析器插件不光可以接受一个布尔值,还能接收一个对象
    默认的插件解析器选项

    parser: {
      amd: false, // 禁用 AMD
      commonjs: false, // 禁用 CommonJS
      system: false, // 禁用 SystemJS
      harmony: false, // 禁用 ES2015 Harmony import/export
      requireInclude: false, // 禁用 require.include
      requireEnsure: false, // 禁用 require.ensure
      requireContext: false, // 禁用 require.context
      browserify: false, // 禁用特殊处理的 browserify bundle
      requireJs: false, // 禁用 requirejs.*
      node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
      node: {...} // 在模块级别(module level)上重新配置 node 层(layer)
    }
    
    Rule.resource

    条件会匹配resource。既可以提供Rule.resource选项,也可以使用快捷选项Rule.test,Rule.exclude和Rule.include

    Rule.rules

    规则数组,当规则匹配时使用

    Rule.test

    Rule.test是Rule.resource.test的简写。如果使用了Rule.test选项,就能使用Rule.resource

    Rule.use

    应用于模块的UseEntries列表。每个入口指定使用一个loader。
    传递字符串(如:use:[‘style-loader’])是loader属性的简写方式(如:user:[{loader:‘style-loader’}])

    条件

    条件可以是:

    • 字符串:匹配输入必须以提供的字符串开始。
    • 正则表达式:test输入值
    • 函数:调用输入的函数,必须返回一个真值以匹配
    • 条件数组:至少一个匹配条件
    • 对象:匹配所有属性。每个属性都有一个定义行为

    条件设置方法:

    1. {test:Condition}:匹配特定条件。一般是提供一个正则表达式或正则表达式的数组,但不强制。
    2. {include:Condition}:匹配特定条件。一般是提供一个字符串或者字符串数组,但不强制
    3. {exclude:Condition}:排除特定条件。一般是提供一个字符串或字符串数组,但不强制
    4. {and:[Condition]}:必须匹配数组中的所有条件
    5. {or:[Condition]}:匹配数组中任何一个条件
    6. {not:[Condition]}:必须排除这个条件
    UseEntry

    类型:object
    必须有一个loader属性是字符串。它使用loader解析选项相对于配置中的context来解析。
    可以有一个options属性为字符串或对象。值可以传递到loader中将其理解为loader选项
    由于兼容性原因,也可能有query属性,这个是options属性的别名,使用options属性替代。
    例子:

    {
    	loader:'css-loader',
    	options:{
    		modules:true
    	}
    }
    

    注意:webpack需要生成资源和所有loader的独立模块标识,包括选项。它尝试对选项对象使用JSON.stringify。这在99.9%的情况下是可以的,但是如果将相同的loader应用于相同资源的不同选项,并且选项具有一些带字符的值,则可能不是唯一的。
    如果选项对象不被字符化(例如循环JSON),它也会中断。可以在选项对象使用identity属性,作为唯一标识符

    解析 [resolve]

    resolve

    类型:object
    配置模块如何解析。例如,当在ES2015中调用import ‘lodash’,resolve选项能够对webpack查找‘lodash’的方式去做修改

    resolve.alias

    类型:Object
    创建import或require的别名,来确定模块引入变得更简单。可以在给定对象的键后的末尾添加$,以精确匹配。
    实例:

    别名 import ‘xyz’ import ‘xyz/file.js’
    {} /abc/node_modules/xyz/index.js /abc/node_modules/xyz/file.js
    {xyz:’/abs/path/to/file.js’} /abs/path/to/file.js error
    { xyz$: “/abs/path/to/file.js” } /abs/path/to/file.js /abc/node_modules/xyz/file.js
    { xyz: “./dir/file.js” } /abc/dir/file.js error
    { xyz$: “./dir/file.js” } /abc/dir/file.js /abc/node_modules/xyz/file.js
    { xyz: “/some/dir” } /some/dir/index.js /some/dir/file.js
    { xyz$: “/some/dir” } /some/dir/index.js /abc/node_modules/xyz/file.js
    resolve.aliasFields

    类型:[string]
    在模块的package.json中指定一个字段,例如browser,按照此规范进行解析。默认:

    aliasFields:['browser']
    
    resolve.cacheWithContext

    类型:boolean(从webpack3.1.0开始)
    如果启用了不安全缓存,请在缓存键(cache key)中引入request.context。这个选项被enhanced-resolve模块考虑在内。从webpack3.1.0开始,在配置了resolve或resolveLoader插件时,解析缓存(resolve caching)中的上下文(context)会被忽略。这解决了性能衰退的问题

    resolve.descriptionFiles

    类型:array
    用于描述的JOSN文件。默认:

    descriptionFiles:['package.json']
    
    resolve.enforceExtension

    类型:boolean
    设置为true,将不允许无扩展名(extension-less)文件。默认如果./foo.js扩展,require('./foo')可以正常运行。但如果启用此选项,只有require('./foo.js')可以正常运行。默认:

    enforceExtension:false
    
    resolve.enforceModuleExtension

    类型:boolean
    对模块是否需要使用的扩展(例如loader)。默认

    enforceModuleExtension:false
    
    resolve.extensions

    类型:array
    自动解析确定的扩展。默认值为:

    extensions:[".js",".json"]
    

    能够使用户在引入模块时不带扩展

    import File from '../path/to/file'
    

    注意:使用此选项,会覆盖默认数组,这就意味着webpack将不再尝试使用默认扩展来解析模块。对于使用其扩展导入的模块,例如,import SomeFile from "./somefile.ext,要想正确的解析,一个包含“*”的字符串必须包含在数组中。

    resolve.mainFields

    类型:array
    当从npm包中导入模块时(例如import * as D3 from ‘d3’),此选项将决定package.json中使用哪个字段导入模块。根据webpack配置中指定的target不同,默认值也会有所不同
    当target属性设置webworker,web或者没有指定,默认值为:

    mainFields:['browser','module','main']
    

    对于其他任意的target(包括node),默认值为:

    mainFields:["module","main"]
    

    实例:
    D3的package.json如下

    {
      main: 'build/d3.Node.js',
      browser: 'build/d3.js',
      module: 'index',
    }
    

    这意味着 import * as D3 from “d3”,实际从 browser 属性解析文件。在这里 browser 属性是最优先选择的,因为它是 mainFields 的第一项。同时,由 webpack 打包的 Node.js 应用程序默认会从 module 字段中解析文件。

    resolve,mainFiles

    类型:array
    解析目录时要使用的文件名,默认:

    mainFiles:["index"]
    
    resolve.modules

    类型:array
    告诉webpack解析模块时应该搜索的目录。
    绝对路径和相对路径都能使用。其中相对路径通过查看当前目录以及祖先路径;使用绝对路径,将只在给定目录中搜索;
    默认值:

    modules:['mode_modules']
    

    如果添加一个目录到模块搜索目录,此目录将优先于node_modules搜索

    modules:[path.resolve(__dirname,"src"),"node_modules"]
    
    resolve.unsafeCache

    类型:regex | array | boolean
    默认:

    unsafeCache:true
    

    启用,会主动缓存模块,单并不安全。传递true将缓存一切
    也可以是正则表达式或者正则表达式数组,可以用于匹配文件路径或只缓存某些模块,例如,只缓存utilities模块

    unsafeCache:/src\/utilities/
    

    注意:修改缓存路径可能在极少数情况下导致失败

    resolve.plugins

    应该使用的额外的解析插件列表。运行使用插件。例子:

    plugins:[
    	new DirectoryNamedWebpackPlugin()
    ]
    
    resolve.symlinks

    类型:boolean
    是否将符号链接解析到对应的符号链接位置。默认值为:

    symlinks:true
    

    启用时,符号链接的资源,将解析为其真实路径,而不是其符号链接位置。
    注意:当使用符号链接package包工具时,可能会导致模块解析失败

    resolve.cachePredicate

    类型:function
    决定请求是否应该被缓存的函数。函数传入一个带有path和request属性的对象。默认:

    cachePredicate:function(){return true}
    

    resolveLoader

    类型:object
    用于解析webpack的loader包,默认:

    {
    	modules:['node_modues'],
    	extensions:['.js','json'],
    	mainFields:['loader','main']
    }
    

    注意:这里可以使用别名,并且其他特性类似于resolve对象。例如,{txt:'row-loader'}会使用raw-loader去shim(填充)txt!templates/demo.txt

    resolveLoader.moduleExtensions

    类型:array
    解析loader时,用到扩展名(extendsions)/后缀(suffixes)。建议使用全名。但是如果想要省略-loader,可以使用此选项实现
    moduleExtensions:[’-loader’]

    插件[plugins]

    plugins选项用于以各种方式自定义webpack构建过程。webpack附带了各种内置插件,可以通过webpack.[plugin-name]访问这些插件。插件列表和对应文档

    plugins

    类型:array
    webpack插件列表
    实例:

    var webpack = require('webpack');
    // 导入非 webpack 自带默认插件
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    var DashboardPlugin = require('webpack-dashboard/plugin');
    
    // 在配置中添加插件
    plugins: [
      // 构建优化插件
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        filename: 'vendor-[hash].min.js',
      }),
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
          drop_console: false,
        }
      }),
      new ExtractTextPlugin({
        filename: 'build.min.css',
        allChunks: true,
      }),
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
      // 编译时(compile time)插件
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': '"production"',
      }),
      // webpack-dev-server 强化插件
      new DashboardPlugin(),
      new webpack.HotModuleReplacementPlugin(),
    ]
    
    展开全文
  • webpack详细步骤

    2020-01-02 11:14:01
    入门(一起来用这些小例子让你熟悉webpack配置) 1.1 初始化项目 新建一个目录,初始化npm npm init webpack是运行在node环境中的,我们需要安装以下两个npm包 npm i -D webpack webpack-cli npm i -D ...

    前言
    一直在用webpack,下面总结一下

    • 入门(一起来用这些小例子让你熟悉webpack的配置)
      1.1 初始化项目
      新建一个目录,初始化npm
    npm init
    

    webpack是运行在node环境中的,我们需要安装以下两个npm包

    npm i -D webpack webpack-cli
    
    • npm i -D 为npm install --save-dev的缩写
    • npm i -S 为npm install --save的缩写

    新建一个文件夹src ,然后新建一个文件main.js,写一点代码测试一下

    console.log('call me nanshen')
    

    配置package.json命令
    20191211104852887.png

    执行

    npm run build
    

    此时如果生成了一个dist文件夹,并且内部含有main.js说明已经打包成功了

    1.2 开始我们自己的配置
    上面一个简单的例子只是webpack自己默认的配置,下面我们要实现更加丰富的自定义配置

    新建一个build文件夹,里面新建一个webpack.config.js

    // webpack.config.js
    
    const path = require('path');
    module.exports = {
        mode:'development', // 开发模式
        entry: path.resolve(__dirname,'../src/main.js'),    // 入口文件
        output: {
            filename: 'output.js',      // 打包后的文件名称
            path: path.resolve(__dirname,'../dist')  // 打包后的目录
        }
    }
    

    更改我们的打包命令
    p2.png

    执行 npm run build
    会发现生成了以下目录(图片)

    其中dist文件夹中的main.js就是我们需要在浏览器中实际运行的文件

    当然实际运用中不会仅仅如此,下面让我们通过实际案例带你快速入手webpack

    1.3 配置html模板
    js文件打包好了,但是我们不可能每次在html文件中手动引入打包好的js

    这里可能有的朋友会认为我们打包js文件名称不是一直是固定的嘛(output.js)?这样每次就不用改动引入文件名称了呀?实际上我们日常开发中往往会这样配置:

    module.exports = {
        // 省略其他配置
        output: {
          filename: '[name].[hash:8].js',      // 打包后的文件名称
          path: path.resolve(__dirname,'../dist')  // 打包后的目录
        }
    }
    

    这时候生成的dist目录文件如下
    p3.png

    为了缓存,你会发现打包好的js文件的名称每次都不一样。webpack打包出来的js文件我们需要引入到html中,但是每次我们都手动修改js文件名显得很麻烦,因此我们需要一个插件来帮我们完成这件事情

    npm i -D html-webpack-plugin
    

    新建一个build同级的文件夹public,里面新建一个index.html

    具体配置文件如下

    // webpack.config.js
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        mode:'development', // 开发模式
        entry: path.resolve(__dirname,'../src/main.js'),    // 入口文件
        output: {
          filename: '[name].[hash:8].js',      // 打包后的文件名称
          path: path.resolve(__dirname,'../dist')  // 打包后的目录
        },
        plugins:[
          new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/index.html')
          })
        ]
    }
    

    生成目录如下(图片)
    p4.png

    可以发现打包生成的js文件已经被自动引入html文件中

    1.3.1. 多入口文件如何开发
    生成多个html-webpack-plugin实例来解决这个问题

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        mode:'development', // 开发模式
        entry: {
          main:path.resolve(__dirname,'../src/main.js'),
          header:path.resolve(__dirname,'../src/header.js')
      }, 
        output: {
          filename: '[name].[hash:8].js',      // 打包后的文件名称
          path: path.resolve(__dirname,'../dist')  // 打包后的目录
        },
        plugins:[
          new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/index.html'),
            filename:'index.html',
            chunks:['main'] // 与入口文件对应的模块名
          }),
          new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/header.html'),
            filename:'header.html',
            chunks:['header'] // 与入口文件对应的模块名
          }),
        ]
    }
    

    此时会发现生成以下目录
    p5.png

    1.3.2 clean-webpack-plugin
    每次执行npm run build 会发现dist文件夹里会残留上次打包的文件,这里我们推荐一个plugin来帮我们在打包输出前清空文件夹clean-webpack-plugin

    const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    module.exports = {
        // ...省略其他配置
        plugins:[new CleanWebpackPlugin()]
    }
    

    1.4 引用CSS
    我们的入口文件是js,所以我们在入口js中引入我们的css文件
    p6.png

    同时我们也需要一些loader来解析我们的css文件

    npm i -D style-loader css-loader
    

    如果我们使用less来构建样式,则需要多安装两个

    npm i -D less less-loader
    

    配置文件如下

    // webpack.config.js
    module.exports = {
        // ...省略其他配置
        module:{
          rules:[
            {
              test:/\.css$/,
              use:['style-loader','css-loader'] // 从右向左解析原则
            },
            {
              test:/\.less$/,
              use:['style-loader','css-loader','less-loader'] // 从右向左解析原则
            }
          ]
        }
    } 
    

    浏览器打开html如下
    p7.png

    1.4.1 为css添加浏览器前缀

    npm i -D postcss-loader autoprefixer
    

    配置如下

    // webpack.config.js
    module.exports = {
        module:{
            rules:[
                test/\.less$/,
                use:['style-loader','css-loader','postcss-loader','less-loader'] // 从右向左解析原则
            ]
        }
    } 
    

    接下来,我们还需要引入autoprefixer使其生效,这里有两种方式

    1,在项目根目录下创建一个postcss.config.js文件,配置如下:

    module.exports = {
        plugins: [require('autoprefixer')]  // 引用该插件即可了
    }
    

    2,直接在webpack.config.js里配置

    // webpack.config.js
    module.exports = {
        //...省略其他配置
        module:{
            rules:[{
                test:/\.less$/,
                use:['style-loader','css-loader',{
                    loader:'postcss-loader',
                    options:{
                        plugins:[require('autoprefixer')]
                    }
                },'less-loader'] // 从右向左解析原则
            }]
        }
    }
    

    这时候我们发现css通过style标签的方式添加到了html文件中,但是如果样式文件很多,全部添加到html中,难免显得混乱。这时候我们想用把css拆分出来用外链的形式引入css文件怎么做呢?这时候我们就需要借助插件来帮助我们

    1.4.2 拆分css

    npm i -D mini-css-extract-plugin
    

    webpack 4.0以前,我们通过extract-text-webpack-plugin插件,把css样式从js文件中提取到单独的css文件中。webpack4.0以后,官方推荐使用mini-css-extract-plugin插件来打包css文件
    配置文件如下

    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    module.exports = {
      //...省略其他配置
      module: {
        rules: [
          {
            test: /\.less$/,
            use: [
               MiniCssExtractPlugin.loader,
              'css-loader',
              'less-loader'
            ],
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
            filename: "[name].[hash].css",
            chunkFilename: "[id].css",
        })
      ]
    }
    

    1.4.3 拆分多个css
    这里需要说的细一点,上面我们所用到的mini-css-extract-plugin会将所有的css样式合并为一个css文件。如果你想拆分为一一对应的多个css文件,我们需要使用到extract-text-webpack-plugin,而目前mini-css-extract-plugin还不支持此功能。我们需要安装@next版本的extract-text-webpack-plugin

    npm i -D extract-text-webpack-plugin@next
    
    // webpack.config.js
    
    const path = require('path');
    const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
    let indexLess = new ExtractTextWebpackPlugin('index.less');
    let indexCss = new ExtractTextWebpackPlugin('index.css');
    module.exports = {
        module:{
          rules:[
            {
              test:/\.css$/,
              use: indexCss.extract({
                use: ['css-loader']
              })
            },
            {
              test:/\.less$/,
              use: indexLess.extract({
                use: ['css-loader','less-loader']
              })
            }
          ]
        },
        plugins:[
          indexLess,
          indexCss
        ]
    }
    

    1.5 打包 图片、字体、媒体、等文件
    file-loader就是将文件在进行一些处理后(主要是处理文件名和路径、解析文件url),并将文件移动到输出的目录中

    url-loader 一般与file-loader搭配使用,功能与 file-loader 类似,如果文件小于限制的大小。则会返回 base64 编码,否则使用 file-loader 将文件移动到输出的目录中

    // webpack.config.js
    module.exports = {
      // 省略其它配置 ...
      module: {
        rules: [
          // ...
          {
            test: /\.(jpe?g|png|gif)$/i, //图片文件
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 10240,
                  fallback: {
                    loader: 'file-loader',
                    options: {
                        name: 'img/[name].[hash:8].[ext]'
                    }
                  }
                }
              }
            ]
          },
          {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 10240,
                  fallback: {
                    loader: 'file-loader',
                    options: {
                      name: 'media/[name].[hash:8].[ext]'
                    }
                  }
                }
              }
            ]
          },
          {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 10240,
                  fallback: {
                    loader: 'file-loader',
                    options: {
                      name: 'fonts/[name].[hash:8].[ext]'
                    }
                  }
                }
              }
            ]
          },
        ]
      }
    }
    

    1.6 用babel转义js文件
    为了使我们的js代码兼容更多的环境我们需要安装依赖

    npm i babel-loader @babel/preset-env @babel/core
    

    注意
    babel-loader与babel-core的版本对应关系

    1. babel-loader 8.x 对应babel-core 7.x
    2. babel-loader 7.x 对应babel-core 6.x

    配置如下

    // webpack.config.js
    module.exports = {
        // 省略其它配置 ...
        module:{
            rules:[
              {
                test:/\.js$/,
                use:{
                  loader:'babel-loader',
                  options:{
                    presets:['@babel/preset-env']
                  }
                },
                exclude:/node_modules/
              },
           ]
        }
    }
    

    上面的babel-loader只会将 ES6/7/8语法转换为ES5语法,但是对新api并不会转换 例如(promise、Generator、Set、Maps、Proxy等)

    此时我们需要借助babel-polyfill来帮助我们转换

    npm i @babel/polyfill
    
    // webpack.config.js
    const path = require('path')
    module.exports = {
        entry: ["@babel/polyfill",path.resolve(__dirname,'../src/index.js')],    // 入口文件
    }
    

    手动把上面的demo敲一遍对阅读下面的文章更有益,建议入门的同学敲三遍以上

    上面的实践是我们对webpack的功能有了一个初步的了解,但是要想熟练应用于开发中,我们需要一个系统的实战。让我们一起摆脱脚手架尝试自己搭建一个vue开发环境

    2. 搭建vue开发环境

    上面的小例子已经帮助而我们实现了打包css、图片、js、html等文件。
    但是我们还需要以下几种配置

    2.1 解析.vue文件

    npm i -D vue-loader vue-template-compiler vue-style-loader
    npm i -S vue
    

    vue-loader 用于解析.vue文件

    vue-template-compiler 用于编译模板
    配置如下

    const vueLoaderPlugin = require('vue-loader/lib/plugin')
    module.exports = {
        module:{
            rules:[{
                test:/\.vue$/,
                use:['vue-loader']
            },]
         },
        resolve:{
            alias:{
              'vue$':'vue/dist/vue.runtime.esm.js',
              ' @':path.resolve(__dirname,'../src')
            },
            extensions:['*','.js','.json','.vue']
       },
       plugins:[
            new vueLoaderPlugin()
       ]
    }
    

    2.2 配置webpack-dev-server进行热更新

    npm i -D webpack-dev-server
    

    配置如下

    const Webpack = require('webpack')
    module.exports = {
      // ...省略其他配置
      devServer:{
        port:3000,
        hot:true,
        contentBase:'../dist'
      },
      plugins:[
        new Webpack.HotModuleReplacementPlugin()
      ]
    }
    

    完整配置如下

    // webpack.config.js
    const path = require('path');
    const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
    const vueLoaderPlugin = require('vue-loader/lib/plugin')
    const Webpack = require('webpack')
    module.exports = {
        mode:'development', // 开发模式
        entry: {
          main:path.resolve(__dirname,'../src/main.js'),
        }, 
        output: {
          filename: '[name].[hash:8].js',      // 打包后的文件名称
          path: path.resolve(__dirname,'../dist')  // 打包后的目录
        },
        module:{
          rules:[
            {
              test:/\.vue$/,
              use:['vue-loader']
            },
            {
              test:/\.js$/,
              use:{
                loader:'babel-loader',
                options:{
                  presets:[
                    ['@babel/preset-env']
                  ]
                }
              }
            },
            {
              test:/\.css$/,
              use: ['vue-style-loader','css-loader',{
                loader:'postcss-loader',
                options:{
                  plugins:[require('autoprefixer')]
                }
              }]
            },
            {
              test:/\.less$/,
              use: ['vue-style-loader','css-loader',{
                loader:'postcss-loader',
                options:{
                  plugins:[require('autoprefixer')]
                }
              },'less-loader']
            }
          ]
        },
        resolve:{
          alias:{
            'vue$':'vue/dist/vue.runtime.esm.js',
            ' @':path.resolve(__dirname,'../src')
          },
          extensions:['*','.js','.json','.vue']
        },
        devServer:{
          port:3000,
          hot:true,
          contentBase:'../dist'
        },
        plugins:[
          new CleanWebpackPlugin(),
          new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/index.html'),
            filename:'index.html'
          }),
          new vueLoaderPlugin(),
          new Webpack.HotModuleReplacementPlugin()
        ]
    }
    

    2.3 配置打包命令
    c4.png

    打包文件已经配置完毕,接下来让我们测试一下

    首先在src新建一个main.js
    c1.png

    新建一个App.vue
    c2.png

    新建一个public文件夹,里面新建一个index.html
    c3.png

    执行npm run dev这时候如果浏览器出现Vue开发环境运行成功,那么恭喜你,已经成功迈出了第一步

    2.4 区分开发环境与生产环境
    实际应用到项目中,我们需要区分开发环境与生产环境,我们在原来webpack.config.js的基础上再新增两个文件

    • webpack.dev.js 开发环境配置文件

    开发环境主要实现的是热更新,不要压缩代码,完整的sourceMap

    • webpack.prod.js生产环境配置文件

    生产环境主要实现的是压缩代码、提取css文件、合理的sourceMap、分割代码
    需要安装以下模块:

    npm i -D  webpack-merge copy-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
    
    • webpack-merge 合并配置
    • copy-webpack-plugin 拷贝静态资源
    • optimize-css-assets-webpack-plugin 压缩css
    • uglifyjs-webpack-plugin 压缩js

    webpack mode设置production的时候会自动压缩js代码。原则上不需要引入uglifyjs-webpack-plugin进行重复工作。但是optimize-css-assets-webpack-plugin压缩css的同时会破坏原有的js压缩,所以这里我们引入uglifyjs进行压缩
    2.4.1 webpack.config.js

    const path = require('path')
    const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const vueLoaderPlugin = require('vue-loader/lib/plugin')
    const MiniCssExtractPlugin = require("mini-css-extract-plugin")
    const devMode = process.argv.indexOf('--mode=production') === -1;
    module.exports = {
      entry:{
        main:path.resolve(__dirname,'../src/main.js')
      },
      output:{
        path:path.resolve(__dirname,'../dist'),
        filename:'js/[name].[hash:8].js',
        chunkFilename:'js/[name].[hash:8].js'
      },
      module:{
        rules:[
          {
            test:/\.js$/,
            use:{
              loader:'babel-loader',
              options:{
                presets:['@babel/preset-env']
              }
            },
            exclude:/node_modules/
          },
          {
            test:/\.vue$/,
            use:[{
              loader:'vue-loader',
              options:{
                compilerOptions:{
                  preserveWhitespace:false
                }
              }
            }]
          },
          {
            test:/\.css$/,
            use:[{
              loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
              options:{
                publicPath:"../dist/css/",
                hmr:devMode
              }
            },'css-loader',{
              loader:'postcss-loader',
              options:{
                plugins:[require('autoprefixer')]
              }
            }]
          },
          {
            test:/\.less$/,
            use:[{
              loader:devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
              options:{
                publicPath:"../dist/css/",
                hmr:devMode
              }
            },'css-loader','less-loader',{
              loader:'postcss-loader',
              options:{
                plugins:[require('autoprefixer')]
              }
            }]
          },
          {
            test:/\.(jep?g|png|gif)$/,
            use:{
              loader:'url-loader',
              options:{
                limit:10240,
                fallback:{
                  loader:'file-loader',
                  options:{
                    name:'img/[name].[hash:8].[ext]'
                  }
                }
              }
            }
          },
          {
            test:/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            use:{
              loader:'url-loader',
              options:{
                limit:10240,
                fallback:{
                  loader:'file-loader',
                  options:{
                    name:'media/[name].[hash:8].[ext]'
                  }
                }
              }
            }
          },
          {
            test:/\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
            use:{
              loader:'url-loader',
              options:{
                limit:10240,
                fallback:{
                  loader:'file-loader',
                  options:{
                    name:'media/[name].[hash:8].[ext]'
                  }
                }
              }
            }
          }
        ]
      },
      resolve:{
        alias:{
          'vue$':'vue/dist/vue.runtime.esm.js',
          ' @':path.resolve(__dirname,'../src')
        },
        extensions:['*','.js','.json','.vue']
      },
      plugins:[
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          template:path.resolve(__dirname,'../public/index.html')
        }),
        new vueLoaderPlugin(),
        new MiniCssExtractPlugin({
          filename: devMode ? '[name].css' : '[name].[hash].css',
          chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
        })
      ]
    }
    2.4.2 webpack.dev.js
    const Webpack = require('webpack')
    const webpackConfig = require('./webpack.config.js')
    const WebpackMerge = require('webpack-merge')
    module.exports = WebpackMerge(webpackConfig,{
      mode:'development',
      devtool:'cheap-module-eval-source-map',
      devServer:{
        port:3000,
        hot:true,
        contentBase:'../dist'
      },
      plugins:[
        new Webpack.HotModuleReplacementPlugin()
      ]
    })
    

    2.4.3 webpack.prod.js

    const path = require('path')
    const webpackConfig = require('./webpack.config.js')
    const WebpackMerge = require('webpack-merge')
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
    module.exports = WebpackMerge(webpackConfig,{
      mode:'production',
      devtool:'cheap-module-source-map',
      plugins:[
        new CopyWebpackPlugin([{
          from:path.resolve(__dirname,'../public'),
          to:path.resolve(__dirname,'../dist')
        }]),
      ],
      optimization:{
        minimizer:[
          new UglifyJsPlugin({//压缩js
            cache:true,
            parallel:true,
            sourceMap:true
        }),
        new OptimizeCssAssetsPlugin({})
        ],
        splitChunks:{
          chunks:'all',
          cacheGroups:{
            libs: {
              name: "chunk-libs",
              test: /[\\/]node_modules[\\/]/,
              priority: 10,
              chunks: "initial" // 只打包初始时依赖的第三方
            }
          }
        }
      }
    })
    

    2.5 优化webpack配置
    看到这里你或许有些累了,但是要想获取更好的offer,更高的薪水,下面必须继续深入
    qiong111.jpg

    优化配置对我们来说非常有实际意义,这实际关系到你打包出来文件的大小,打包的速度等。
    具体优化可以分为以下几点:

    2.5.1 优化打包速度
    构建速度指的是我们每次修改代码后热更新的速度以及发布前打包文件的速度。
    2.5.1.1 合理的配置mode参数与devtool参数
    mode可设置development production两个参数

    如果没有设置,webpack4 会将 mode 的默认值设置为 production
    production模式下会进行tree shaking(去除无用代码)和uglifyjs(代码压缩混淆)

    2.5.1.2 缩小文件的搜索范围(配置include exclude alias noParse extensions)

    • alias: 当我们代码中出现 import 'vue’时, webpack会采用向上递归搜索的方式去node_modules
      目录下找。为了减少搜索范围我们可以直接告诉webpack去哪个路径下查找。也就是别名(alias)的配置。

    • include exclude 同样配置include exclude也可以减少webpack loader的搜索转换时间。

    • noParse 当我们代码中使用到import jq from

    • 'jquery’时,webpack会去解析jq这个库是否有依赖其他的包。但是我们对类似jquery这类依赖库,一般会认为不会引用其他的包(特殊除外,自行判断)。增加noParse属性,告诉webpack不必解析,以此增加打包速度。

    • extensions webpack会根据extensions定义的后缀查找文件(频率较高的文件类型优先写在前面)

    carbon-2.png

    2.5.1.3 使用HappyPack开启多进程Loader转换
    在webpack构建过程中,实际上耗费时间大多数用在loader解析转换以及代码的压缩中。日常开发中我们需要使用Loader对js,css,图片,字体等文件做转换操作,并且转换的文件数据量也是非常大。由于js单线程的特性使得这些转换操作不能并发处理文件,而是需要一个个文件进行处理。HappyPack的基本原理是将这部分任务分解到多个子进程中去并行处理,子进程处理完成后把结果发送到主进程中,从而减少总的构建时间

    npm i -D happypack
    

    carbon-3.png

    2.5.1.4 使用webpack-parallel-uglify-plugin 增强代码压缩
    上面对于loader转换已经做优化,那么下面还有另一个难点就是优化代码的压缩时间。

    npm i -D webpack-parallel-uglify-plugin
    

    carbon-4.png

    2.5.1.5 抽离第三方模块
    对于开发项目中不经常会变更的静态依赖文件。类似于我们的elementUi、vue全家桶等等。因为很少会变更,所以我们不希望这些依赖要被集成到每一次的构建逻辑中去。 这样做的好处是每次更改我本地代码的文件的时候,webpack只需要打包我项目本身的文件代码,而不会再去编译第三方库。以后只要我们不升级第三方包的时候,那么webpack就不会对这些库去打包,这样可以快速的提高打包的速度。
    这里我们使用webpack内置的DllPlugin DllReferencePlugin进行抽离

    在与webpack配置文件同级目录下新建webpack.dll.config.js
    代码如下

    // webpack.dll.config.js
    const path = require("path");
    const webpack = require("webpack");
    module.exports = {
      // 你想要打包的模块的数组
      entry: {
        vendor: ['vue','element-ui'] 
      },
      output: {
        path: path.resolve(__dirname, 'static/js'), // 打包后文件输出的位置
        filename: '[name].dll.js',
        library: '[name]_library' 
         // 这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
      },
      plugins: [
        new webpack.DllPlugin({
          path: path.resolve(__dirname, '[name]-manifest.json'),
          name: '[name]_library', 
          context: __dirname
        })
      ]
    };
    

    在package.json中配置如下命令

    "dll": "webpack --config build/webpack.dll.config.js"
    接下来在我们的webpack.config.js中增加以下代码
    
    module.exports = {
      plugins: [
        new webpack.DllReferencePlugin({
          context: __dirname,
          manifest: require('./vendor-manifest.json')
        }),
        new CopyWebpackPlugin([ // 拷贝生成的文件到dist目录 这样每次不必手动去cv
          {from: 'static', to:'static'}
        ]),
      ]
    };
    

    执行

    npm run dll
    

    会发现生成了我们需要的集合第三地方
    代码的vendor.dll.js
    我们需要在html文件中手动引入这个js文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>老yuan</title>
      <script src="static/js/vendor.dll.js"></script>
    </head>
    <body>
      <div id="app"></div>
    </body>
    </html>
    

    这样如果我们没有更新第三方依赖包,就不必npm run dll。直接执行npm run dev npm run build的时候会发现我们的打包速度明显有所提升。因为我们已经通过dllPlugin将第三方依赖包抽离出来了。

    2.5.1.6 配置缓存
    我们每次执行构建都会把所有的文件都重复编译一遍,这样的重复工作是否可以被缓存下来呢,答案是可以的,目前大部分 loader 都提供了cache 配置项。比如在 babel-loader 中,可以通过设置cacheDirectory 来开启缓存,babel-loader?cacheDirectory=true 就会将每次的编译结果写进硬盘文件(默认是在项目根目录下的node_modules/.cache/babel-loader目录内,当然你也可以自定义)

    但如果 loader 不支持缓存呢?我们也有方法,我们可以通过cache-loader ,它所做的事情很简单,就是 babel-loader 开启 cache 后做的事情,将 loader 的编译结果写入硬盘缓存。再次构建会先比较一下,如果文件较之前的没有发生变化则会直接使用缓存。使用方法如官方 demo 所示,在一些性能开销较大的 loader 之前添加此 loader即可

    npm i -D cache-loader
    

    carbon-5.png

    2.5.2 优化打包文件体积
    打包的速度我们是进行了优化,但是打包后的文件体积却是十分大,造成了页面加载缓慢,浪费流量等,接下来让我们从文件体积上继续优化
    2.5.2.1 引入webpack-bundle-analyzer分析打包后的文件
    webpack-bundle-analyzer将打包后的内容束展示为方便交互的直观树状图,让我们知道我们所构建包中真正引入的内容

    npm i -D webpack-bundle-analyzer
    

    carbon-6.png

    接下来在package.json里配置启动命令

    "analyz": "NODE_ENV=production npm_config_report=true npm run build"
    

    windows请安装npm i -D cross-env

    "analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
    

    接下来npm run analyz浏览器会自动打开文件依赖图的网页

    2.5.2.3 externals
    按照官方文档的解释,如果我们想引用一个库,但是又不想让webpack打包,并且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置Externals。这个功能主要是用在创建一个库的时候用的,但是也可以在我们项目开发中充分使用
    Externals的方式,我们将这些不需要打包的静态资源从构建逻辑中剔除出去,而使用 CDN
    的方式,去引用它们。

    有时我们希望我们通过script引入的库,如用CDN的方式引入的jquery,我们在使用时,依旧用require的方式来使用,但是却不希望webpack将它又编译进文件中。这里官网案例已经足够清晰明了,大家有兴趣可以点击了解

    webpack

    官网案例如下

    <script>
      src="https://code.jquery.com/jquery-3.1.0.js"
      integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
      crossorigin="anonymous">
    </script>
    
    module.exports = {
      //...
      externals: {
        jquery: 'jQuery'
      }
    };
    
    import $ from 'jquery';
    $('.my-element').animate(/* ... */);
    

    2.5.2.3 Tree-shaking
    这里单独提一下tree-shaking,是因为这里有个坑。tree-shaking的主要作用是用来清除代码中无用的部分。目前在webpack4 我们设置mode为production的时候已经自动开启了tree-shaking。但是要想使其生效,生成的代码必须是ES6模块。不能使用其它类型的模块如CommonJS之流。如果使用Babel的话,这里有一个小问题,因为Babel的预案(preset)默认会将任何模块类型都转译成CommonJS类型。修正这个问题也很简单,在.babelrc文件或在webpack.config.js文件中设置modules: false就好了

    // .babelrc
    {
      "presets": [
        ["@babel/preset-env",
          {
            "modules": false
          }
        ]
      ]
    }
    

    或者

    // webpack.config.js
    
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', { modules: false }]
                    }
                },
                exclude: /(node_modules)/
            }
        ]
    }
    

    经历过上面两个系列的洗礼,到现在我们成为了一名合格的webpack配置工程师。但是光拧螺丝,自身的可替代性还是很高,下面我们将深入webpack的原理中去
    TEST3.png

    3.手写webpack系列

    经历过上面两个部分,我们已经可以熟练的运用相关的loader和plugin对我们的代码进行转换、解析。接下来我们自己手动实现loader与plugin,使其在平时的开发中获得更多的乐趣。
    3.1 手写webpack loader
    loader从本质上来说其实就是一个node模块。相当于一台榨汁机(loader)将相关类型的文件代码(code)给它。根据我们设置的规则,经过它的一系列加工后还给我们加工好的果汁(code)。
    loader编写原则

    • 单一原则: 每个 Loader 只做一件事;
    • 链式调用: Webpack 会按顺序链式调用每个 Loader;
    • 统一原则: 遵循 Webpack 制定的设计规则和结构,输入与输出均为字符串,各个 Loader 完全独立,即插即用;

    在日常开发环境中,为了方便调试我们往往会加入许多console打印。但是我们不希望在生产环境中存在打印的值。那么这里我们自己实现一个loader去除代码中的console

    知识点普及之AST。AST通俗的来说,假设我们有一个文件a.js,我们对a.js里面的1000行进行一些操作处理,比如为所有的await 增加try catch,以及其他操作,但是a.js里面的代码本质上来说就是一堆字符串。那我们怎么办呢,那就是转换为带标记信息的对象(抽象语法树)我们方便进行增删改查。这个带标记的对象(抽象语法树)就是AST。这里推荐一篇不错的AST文章 AST快速入门

    npm i -D @babel/parser @babel/traverse @babel/generator @babel/types
    
    • @babel/parser 将源代码解析成 AST

    • @babel/traverse 对AST节点进行递归遍历,生成一个便于操作、转换的path对象

    • @babel/generator 将AST解码生成js代码

    • @babel/types通过该模块对具体的AST节点进行进行增、删、改、查

    新建 drop-console.js

    const parser = require('@babel/parser')
    const traverse = require('@babel/traverse').default
    const generator = require('@babel/generator').default
    const t = require('@babel/types')
    module.exports=function(source){
      const ast = parser.parse(source,{ sourceType: 'module'})
      traverse(ast,{
        CallExpression(path){ 
          if(t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object, {name: "console"})){
            path.remove()
          }
        }
      })
      const output = generator(ast, {}, source);
      return output.code
    }
    

    如何使用

    const path = require('path')
    module.exports = {
      mode:'development',
      entry:path.resolve(__dirname,'index.js'),
      output:{
        filename:'[name].[contenthash].js',
        path:path.resolve(__dirname,'dist')
      },
      module:{
        rules:[{
          test:/\.js$/,
          use:path.resolve(__dirname,'drop-console.js')
          }
        ]
      }
    }
    

    实际上在webpack4中已经集成了去除console功能,在minimizer中可配置 去除console
    附上官网 如何编写一个loader

    3.2 手写webpack plugin
    在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果。通俗来说:一盘美味的 盐豆炒鸡蛋 需要经历烧油 炒制 调味到最后的装盘等过程,而plugin相当于可以监控每个环节并进行操作,比如可以写一个少放胡椒粉plugin,监控webpack暴露出的生命周期事件(调味),在调味的时候执行少放胡椒粉操作。那么它与loader的区别是什么呢?上面我们也提到了loader的单一原则,loader只能一件事,比如说less-loader,只能解析less文件,plugin则是针对整个流程执行广泛的任务。
    一个基本的plugin插件结构如下

    class firstPlugin {
      constructor (options) {
        console.log('firstPlugin options', options)
      }
      apply (compiler) {
        compiler.plugin('done', compilation => {
          console.log('firstPlugin')
        ))
      }
    }
    
    module.exports = firstPlugin
    

    compiler 、compilation是什么?
    compiler 对象包含了 Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
    compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
    compiler和 compilation的区别在于

    compiler代表了整个webpack从启动到关闭的生命周期,而compilation只是代表了一次新的编译过程
    compiler和compilation暴露出许多钩子,我们可以根据实际需求的场景进行自定义处理
    compiler钩子文档
    compilation钩子文档

    下面我们手动开发一个简单的需求,在生成打包文件之前自动生成一个关于打包出文件的大小信息

    新建一个webpack-firstPlugin.js

    class firstPlugin{
      constructor(options){
        this.options = options
      }
      apply(compiler){
        compiler.plugin('emit',(compilation,callback)=>{
          let str = ''
          for (let filename in compilation.assets){
            str += `文件:${filename}  大小${compilation.assets[filename]['size']()}\n`
          }
          // 通过compilation.assets可以获取打包后静态资源信息,同样也可以写入资源
          compilation.assets['fileSize.md'] = {
            source:function(){
              return str
            },
            size:function(){
              return str.length
            }
          }
          callback()
        })
      }
    }
    module.exports = firstPlugin
    

    如何使用

    const path = require('path')
    const firstPlugin = require('webpack-firstPlugin.js')
    module.exports = {
        // 省略其他代码
        plugins:[
            new firstPlugin()
        ]
    }
    

    执行 npm run build即可看到在dist文件夹中生成了一个包含打包文件信息的fileSize.md

    上面两个loader与plugin案例只是一个引导,实际开发需求中的loader与plugin要考虑的方面很多,建议大家自己多动手尝试一下。
    附上官网 如何编写一个plugin

    3.3 手写webpack
    由于篇幅过长,且原理深入较多。鉴于本篇以快速上手应用于实际开发的原则,这里决定另起一篇新的文章去详细剖析webpack原理以及实现一个demo版本。待格式校准后,将会贴出文章链接在下方

    4. webpack5.0的时代

    无论是前端框架还是构建工具的更新速度远远超乎了我们的想象,前几年的jquery一把梭的时代一去不复返。我们要拥抱的是不断更新迭代的vue、react、node、serverless、docker、k8s…

    在这里插入图片描述

    不甘落后的webpack也已经在近日发布了 webpack 5.0.0 beta 10 版本。在之前作者也曾提过webpack5.0旨在减少配置的复杂度,使其更容易上手(webpack4的时候也说了这句话),以及一些性能上的提升

    • 使用持久化缓存提高构建性能;
    • 使用更好的算法和默认值改进长期缓存(long-term caching);
    • 清理内部结构而不引入任何破坏性的变化;
    • 引入一些breaking changes,以便尽可能长的使用v5版本。

    目前来看,维护者的更新很频繁,相信用不了多久webpack5.0将会拥抱大众。感兴趣的同学可以先安装beta版本尝尝鲜。不过在此之前建议大家先对webpack4进行一番掌握,这样后面的路才会越来越好走。

    原文链接

    展开全文
  • Vue-cli3项目 配置webpack (Vue.config.js)

    万次阅读 2018-11-27 10:05:05
    1.webpack配置路径别名 2.webpack全局注入通用样式 3.webpack引入第三方插件,如Amap,QRcode等 在项目的根目录下新建 vue.config.js 文件(是根目录,不是src目录),如图: 配置实例如下: const path = ...
    1.webpack配置路径别名
    
    2.webpack全局注入通用样式
    
    3.webpack引入第三方插件,如Amap,QRcode等
    

    在项目的根目录下新建 vue.config.js 文件(是根目录,不是src目录),如图:
    在这里插入图片描述

    配置实例如下:

    const path = require('path')
    const resolve = dir => path.join(__dirname, dir)
    const fs = require('fs')
    
    module.exports = {
      baseUrl: './',
      runtimeCompiler: true,
      // 配置路径别名
      chainWebpack: config => {
        config.resolve.alias
          .set('@', resolve('src'))
          .set('_c', resolve('src/components/'))
          .set('_as', resolve('src/assets/img/'))
      },
      // 传递第三方插件选项
      pluginOptions: {
        'AMap': 'AMap',
        'QRCode': 'QRCode'
      },
      // 全局注入通用样式
      css: {
        loaderOptions: {
          stylus: {
            data: fs.readFileSync('./src/assets/stylus/mixins.styl', 'utf-8')
          }
        }
      }
    }
    
    

    具体见官方文档 https://cli.vuejs.org/zh/config/#vue-config-js

    展开全文
  • 官方插件的使用步骤(内置插件 2 步) 1 配置文件中导入 XxxxPlugin,constwp=require(XxxxPlugin) 2 在 plugins 这个数组中加入一个插件实例,newwp.XxxxPlugin({对象}) 第三方插件的使用步骤(第

    重点插件plugin介绍

    插件与模块解析的功能不一样, 模块解析是为了导入非es5格式js或其它资源类型文件, 定制了一些loader。 插件是对最后的打包文件进行处理的,也可以理解loader是为打包前做准备,plugin是打包再进行处理

    • 官方插件的使用步骤(内置插件 2 步) 1 配置文件中导入 XxxxPlugin,constwp=require(XxxxPlugin) 2 在 plugins 这个数组中加入一个插件实例,newwp.XxxxPlugin({对象})

    • 第三方插件的使用步骤(第 3 方 3 步,多一次安装) 1 安装(第三方插件要安装)根目录>cnpmi-DXxxxPlugin 2 配置文件中导入插件constXxxxPlugin=require(‘xxxx-plugin’) 3 在 plugins 这个数组中加入一个插件实例,newXxxxPlugin({对象})

    • 官方插件有
      可以在配置中打印查看 constwebpack=require(‘webpack’) console.log(webpack)//这里可以看到哪些是 webpack 内置的插件

    插件清单

    > 01.webpack.BannerPlugin //加注释  
    > 02.terser-webpack-plugin //代码缩小,压缩   
    > 03.html-webpack-plugin 生成html页  
    > 04.extract-text-webpack-plugin,mini-css-extract-plugin //提取抽离css
    > 05.DefinePlugin//定义一个全局常量,如newwp.DefinePlugin({BJ:JSON.stringify('北京'),}),在待打包的js文件中可以
    > 直接使用,如在./src/main.js中console.log('我是在配置文件中定义的'+BJ) 
    > 06.Dllplugins // 允许创建一个在编译时可以配置的全局常量
    > 07.copy-webpack-plugin //在 webpack中拷贝文件和文件夹
    > 08.optimize-css-assets-webpack-plugin // 压缩css
    > 09.assets-webpack-plugin // assets-webpack-plugin 
    > 10:EnvironmentPlugin//不同于 DefinePlugin,默认值将被 EnvironmentPlugin 执行 JSON.stringify
    > 11.cross-env //scripts设置环境变量
    > 12.ProvidePlugin//微服务api配置
    > 13.preload-webpack-plugin //让静态资源支持 DNS 预解析和预加载
    
    展开全文
  • vue2.x @vue/cli3 配置路径别名

    千次阅读 2020-09-28 10:34:07
    文章目录问题描述vue.config.js 如何配置路径别名使用自定义的新路径别名 问题描述 工作中,想在Vue 工程中启动webpack打包的时候,传一个配置参数给浏览器 这样浏览器环境根据 配置的参数 就可以区分环境,例如: ...
  • Webpack入门

    万次阅读 2016-08-11 11:24:47
    Webpack 是什么webpack是一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理。 简单说就是模块加载器,通过使用Webpack,能够像Node.js一样...
  • 随着各大技术(vue,webpack,react,微信小程序)生态越来越成熟,这也...或许这就是面试官要问你的问题:请手写一个webpack4.0的配置。  webpack详解 webpack是一个打包工具,他的宗旨是一切静态资源即可打包。...
  • webpack4实用配置指南-上手篇

    万次阅读 2018-08-23 17:13:48
    工具用法的东西,好记性不如烂笔头,有必要系统梳理下webpack配置常用配置以及构建优化。 分为上手篇和优化篇,本篇为上手篇,先介绍常用配置。 篇幅较长,可完整阅读,也可在遇到问题时即查即用。 此次采用...
  • webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js 一开始在接触webpack 的时候,简直痛不欲生,现在回头看,做个注释, 当然参考了很多文章。这是一个关于vue 开发的webpack 架构会列举出来 webpack...
  • 基于Webpack的Cesium+Vue应用

    万次阅读 多人点赞 2018-04-10 22:08:16
    这是一篇关于如何通过Webpack配置快速将Vue-cli脚手架与Cesium库整合,最终目的是可以使用Vue+Cesium进行组合编写代码,并可以正确打包Cesium的代码。 Cesium.js是一个渲染三维地球的JavaScript库。它可以实现...
  • webpack-2-基本配置

    千次阅读 2017-06-30 09:59:00
    webpack 2 基本配置,DevServer 配置说明 最近重构代码时,把 webpack 升级到了 2.2.1,结果完全无法运行,正好看到了这份文档,讲解的很详细,所以就学习了一下,应用到项目中。 列出版本 “webpack”: “^2.2.1”...
  • 在vue项目中配置webpack

    千次阅读 2019-05-19 13:54:41
    Webpack在vue项目中的配置 1.使用webpack的必要性 在刚接触 webpack 的时候一直觉得这个打包工具是个可有可无的东西,不仅要写许多的配置代码,还要安装各种插件来使用。后来接触的次数多了,觉得如果没有 webpack ...
  • 一、认识webpack 官方网址:https://www.webpackjs.com/ 1.什么是webpack webpack是一个前端模块化打包工具 2.前端模块化 3.和grunt/gulp打包工具的对比 grunt/gulp更强调的是自动化、定义一些任务 webpack更强调...
  • 这里建议刚学vue的同学第一个小案例不要使用vue-cli进行操作,待对基本的api使用的比较顺手了之后再进行vue-cli的体验比较好。本人是一名后端开发人员,接触前端时间不长,这里有说的不好的地方,还请大家评论建议下...
  • webpack编译流程漫谈

    千次阅读 2016-09-03 17:06:51
    本篇文章是个人对webpack的一点小研究总结。 webpack在开发者社区的反馈 类似gulp把自己定位为stream building tools一样,webpack把自己定位为module building system。在webpack看来,所有
  • webpack概念以及配置文件详解

    千次阅读 2018-03-02 14:41:04
    Webpack 概念 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个...
  • React+ES6+Less+Bootstrap----webpack初探

    千次阅读 2016-04-12 12:10:08
    杂谈从gulp到webpack,我一路上跌跌撞撞,试图寻找一种属于我的懒惰模式。然而,现实往往并不乐观。去年学长玩gulp时,我还只是个只关心今天的阳光是否灿烂,吹起的暖风是否宜人的孩子····哦,我会一直以一个...
  • 1、看完了 underscore.js 的源码,分析了下公司项目中在vue-cli基础上扩展的一些webpack配置 2、开始了学习react,并利用 react 开始重写自己的新博客项目了,这次要好好做了,技术栈的话就 react react-router ...
  • webpack4打包优化配置

    千次阅读 2019-06-11 19:54:33
    1、对图片进行压缩和...image-webpack-loader可以帮助我们对图片进行压缩和优化 cnpm install image-webpack- --save-dev 复制代码 { test: /\.(png|svg|jpg|gif|jpeg|ico)$/, use: [ 'file-loader', { loade...
  • 总结别人对webpack的理解

    千次阅读 2018-05-09 10:07:40
    转自:https://blog.csdn.net/liujie19901217/article/details/51026943webpack就是一切都可以当成模块,require引入,不是js的通过loader解释一下,然后打包到一个js文件,html页面在script引入它,那么大的js只是...
1 2 3 4 5 ... 20
收藏数 2,340
精华内容 936
关键字:

webpack 完整案例 配置别名