Qidian-mix的webpack配置

Qidian-mix

webpack 2.7

1. 这些配置干了啥

2. 为啥要这么配置

3. 为啥我看不懂 ?

4. 从头开始自己动手配置

演示的示例页面:

https://oaadmin.qidian.qq.com/ea/customer/leads/index

核心配置

entry: bundle的入口

path: 输出文件的路径(绝对路径)

publicPath: 输出文件在HTML文件中被引用的路径

path D:\work\qidian-mix\public\cdn
publicPath /

PublicPath  在有些loader中也有 例如img-loader

这个设置

1. 是打包后js文件在承载html页面中被引用的路径

2. 如果在img-loader中是图片文件被html中img标签src引用的路径

以entry为起点 对应一个bundle

通过语法解析 import语句, import函数 , require

来产生依赖树createGraph

 

bundle不一定只有一个文件

1.可以通过import函数来产生一个单独的子chunk(code-split)

2.通过commonChunk把重复引用的文件和Node-modules中的文件单独提取到一个文件中

3.通过extract-text-webpack-plugin提取出js中css成单独的css文件

Loader

test
use

 

test: /\.less$/,
include: [
    SRC_DIR
],
use: extractCSS.extract({
    fallback: 'style-loader',
    use: [
        {
            loader: 'css-loader',
            options: {
                modules: true,
                importLoaders: 1,
                localIdentName: cssModuleName
            }
        },
        {
            loader: 'postcss-loader',
            options: {
                plugins: (loader) => [
                    require('stylelint')(),
                    require('postcss-touch-callout')(),
                    require('autoprefixer')(),
                    ... (isProduction ? [require('cssnano')({
                        zindex: false,
                        discardComments: {
                            removeAll: true
                        }
                    })] : [])
                ]
            }
        },
        'less-loader'
    ]
})
I: 原始模块代码
O: 被webpack理解的模块内容
插件往往在loader中
对文件做操作

babel-loader:   js

vue-loader:  vue

sass/less/css-loader:  css

raw-loader:  file

img-loader: svg png

bundle文件划分

1.vendor 从bundle中提取出来的公用内容

2.code-split 把业务逻辑单独打一个包 chunk

route.push({
    path: '/customer/leads/index',
    name: 'index',
    meta: {
        title: '潜客库 - 腾讯企点'
    },
    component: r => require.ensure([], () => {
        r(require('./customer/leads/index.vue'));
        return null;
    }, 'leads')
});

注意这里的requre.ensure(废弃)

webpack 4 用import函数

Code Split

ExtractTextPlugin 在loader中被调用

CommonsChunkPlugin 在dev和prod的配置不同

排除其他业务逻辑

 

webpack的官方介绍是一个单页应用打包的工具但是实际上我们也用它提供的一些插件做了一些文件搬迁,文件打zip包等操作,这些都和打包过程无关,只是工程的自动化操作

在 node dev-server.js 时

很多操作是用express实现的,其实也和打包逻辑无关

虽然用到了webpack的express的一些中间件
例如dev-server 和 hot-module

还有render来渲染模板, mock接口和socket.io

但这些也和打包流程无关

 

其他

红色的构建配置 ,黄色的是发布和提交配置,绿色是模板

node dev-server.js

打包出来的文件:

此时没有用

require.ensure 做code-split

如之前所说基本的配置是不会从3 中提取出 2 和 4 的

1.ivr.js (bundle)

2.manifest   (chunk) 是从IVR.js中通过commonChunk插件分离出来的公用JS

3.call_ivr.css (Chunk) 从js中提取出来的css

4.base.css (非打包内容)  express staic 的静态文件

本地看打不到这些文件

因为我们把编辑结果放到了express的中间件中

为什么要这么做

1.通过devMiddlewave 把编译出来的文件以webpackConfig.output.publicPath 对应的 static 路径

挂载到了express 中

2.因此也可以使用HotMiddlewav做热更新

3.webpack对实际文件io操作非常费时间,如果每次都生成实际文件io开销非常的大,会浪费时间

4.到这里为止就可以通过

localhost:{端口号}+ {outputPath} + {filename }

来访问到webpack打包出的文件了

但是这种方式不太方便调试

我们想看打包出来的文件怎么办呢

var webpackConfig = require('./webpack.dev.conf')

// 这种模式下webpack的只load了配置并没有执行打包 
var compiler = webpack(webpackConfig)
/* 
//  如果在webpack() 函数上传入callback 默认就相当于 compiler.run(callback)
var compiler = webpack(webpackConfig, (err, state) => {
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }) + '\n\n')
})*/
compiler.run((err. state) => {
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }) + '\n\n')
})

1. webpack 的run命令非常奇怪如果在webpack中加callback会默认执行run,如果不加callback只是读取配置

2. 编译会和dev-server中的hot-module触发的编译冲突(错误)

3. node build-dev.js 记得把配置指向 webpack.dev.config

生成实际文件

 

注意: 到这里为止 没有对html做任何处理,也没有生成模板 也没有把bundle插入到html中

 

但是到此为止打包的过程和生成Js包的核心流程就走完了

 

这些Js是怎么放到html中的呢?

在 node dev-server时 通过 new HtmlWebpackPlugin(conf)

var pages = utils.getEntries('./src/pages/**/main.js');
for(var page in pages) {
// 配置生成的html文件,定义路径等
console.log('page',page)
console.log(page);
var conf = {
  alwaysWriteToDisk: true,
  filename: '../../src/views/' + page + '/index.html',
  template: page.indexOf('mobile') === 0 ? `!!raw-loader!./static/mobile/online.html` : `!!raw-loader!./static/page.html`, //模板路径
  inject: true,
  excludeChunks: Object.keys(pages).filter(item => {
    return (item != page)
  })
}
// 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
module.exports.plugins.push(new HtmlWebpackPlugin(conf))
}

js 会被 写入到 views 中 call/ea/ivr 目录下的index.html 中

此时使用了htmlPlugin.js一个我们自定义的生命周期钩子调用来改写了css和js输出的路径

把view的模板和数据render到一起

这里可以看到访问ivr时

访问的viewPath是/call/ivr.index.html

数据为dev下对应页面的框架机默认数据

实际上这里还有mock数据的配置

注意:其实在webpack.prod.conf 中

并没有生成框架机模板

生产上的框架机模板(views目录下)其实是

我们每次run dev时生成的

为什么会有这个历史问题呢

node build-prod

Take a glimpse 

\public\cdn\static\

 webpack.prod.conf  比 webpack.dev.conf 多的内容

1.loader中把img-loader的PublicPath从static目录改成了一个相对路径(因为根域名变化)

2.关闭了sourceMap

3.output.chunkFilename 的名称加了hash(注意fileName没加)

4.增加了UglifyJsPlugin压缩css, OptimizeCSSPlugin去除重复css 加prefix等

5.复制和生成了几个静态文件

 

但是却没有了重新生成views文件夹下的html文件

因此页面上只有ivr-hash的文件带有hash值

因为我们现在框架机在git上

每次qidian-mix的views更新不好同步过去

所以两边都取消了文件上的hash

chunkFile leash-hash.js因为是在manifest中加载所以有hash

html中无hash导致的缓存问题

客户端缓存无法更新

cdn也没法更新

我们的本地缓存过期时间只能设置的很短

插件 & 自定义插件

compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) {
        //console.log(htmlPluginData);
        //console.log(htmlPluginData.assets)

        htmlPluginData.assets.css = htmlPluginData.assets.css.map((css)=>{
            return '//<%== _domain %><%== locals.base %>' + css +  '<%== locals.lbfConf.comboSuffix %>';
        });
        htmlPluginData.assets.js = htmlPluginData.assets.js.map((js)=>{
            return '//<%== _domain %><%== locals.base %>' + js  +  '<%== locals.lbfConf.comboSuffix %>' ;
        });
        
        callback(null, htmlPluginData);
    });

1. 在html-webpack-plugin-before-html-processing,after  等生命周期钩子中对buffer中的compilation(通过这个对象可以读取到所有打包中内容)对象做处理

2. 还有其他生命周期钩子和异步钩子等(调用方式随版本不同)

3. 之前我们提到我们有提取CSS的插件,插入html,提取公共依赖js的插件只是官方提供的插件的一小部分

调试   npm run build --report

可视化的显示文件的关系

可视化的显示文件中的依赖树

如果我们自己写一个构建配置我们需要什么呢

1.本地开发server:支持热更新,本地服务端渲染,反向代理配置,mock数据,解决打包的效率问题

 

2.不同环境的打包过程:

测试环境:sourceMap

生产环境:代码压缩,代码分割,剔除重复依赖,路径替换

 

3.自定义的构建过程

4.自动化处理 : 自动增删,替换,移动文件

一些需要解决的

1.分析依赖树,剔除重复文件

2.生成commontrunk时先生成一个动态链接库(vendor或者ltc)再来生成manifest,增加打包速度

github上的项目模板:https://github.com/mrzhuzhe/nerd

基于webpack4.0

希望大家能来给我提issue

End

qidian-mix的webpack配置解释qidian 服务的grunt 配置

By zhe zhu

qidian-mix的webpack配置解释qidian 服务的grunt 配置

  • 1,116