• webpack2配置


    详细的配置可以参考官网:https://doc.webpack-china.org/guides/

    一开始做项目时都是直接从组里前辈搭建好的脚手架开始写代码,到后来自己写新项目时又是拷贝之前的工程作为脚手架开始。对于脚手架本身却不甚了解,不仅不思考为什么更是没有改进的想法,怪不得工作满一年了却总觉得自己的技术水平在原地踏步,就是没有总结和思考。

    目前组里的技术栈都是使用vue+koa,使用webpack的好处一是方便写vue的单文件组件,二是打包文件方便生产部署再加上能无所顾虑的应用语言的新特性。

    1. 配置文件

    官方文档推荐写webpack配置文件时,先写出一个基本配置文件(base)包含入口、输出等,再根据开发/生产环境所需要插件的不同,利用webpack-merge生成三个配置文件: dev、prod、analyze

    package.json 依赖参考

    "devDependencies": {
        "babel-core": "^6.18.2",
        "babel-loader": "^7.1.1",
        "babel-preset-es2015": "^6.18.0",
        "css-loader": "^0.28.4",
        "koa-webpack-dev-middleware": "^1.4.0",
        "koa-webpack-hot-middleware": "^1.0.3",
        "less": "^2.7.1",
        "less-loader": "^4.0.5",
        "style-loader": "^0.18.2",
        "url-loader": "^0.5.7",
        "vue-loader": "^12.2.2",
        "webpack": "^3.3.0",
        "webpack-bundle-analyzer": "^2.8.3",
        "webpack-dev-middleware": "^1.11.0",
        "webpack-dev-server": "^2.6.1",
        "webpack-hot-middleware": "^2.13.1",
        "webpack-koa-hot-middleware": "^0.1.2",
        "webpack-manifest-plugin": "^1.2.1",
        "webpack-merge": "^4.1.0"
      }

    webpack.config.base.js

     1 'use strict'
     2 let path = require('path');
     3 let webpack = require('webpack');
     4 let WebpackManifestPlugin = require("webpack-manifest-plugin");
     5 
     6 module.exports = {
     7     output: {
     8         path: path.resolve(__dirname, '..', 'build')
     9     },
    10     resolve: {
    11         extensions: ['.js', '.vue'],
    12         modules: ['node_modules'],
    13         alias: {
    14             'leafletCSS': 'leaflet/dist/leaflet.css',
    15             'leaflet$': 'leaflet/dist/leaflet.js',
    16             'vue$': 'vue/dist/vue.min.js',
    17             'vue-resource$': 'vue-resource/dist/vue-resource.min.js'
    18         }
    19     },
    20     module: {
    21         rules: [
    22             {
    23                 test: /.vue$/,
    24                 loader: 'vue-loader',
    25             },
    26             {
    27                 test: /.js$/,
    28                 exclude: /(node_modules|bower_components)/,
    29                 use: {
    30                     loader: 'babel-loader',
    31                     options: {
    32                         presets: ['es2015']
    33                     }
    34                 }
    35             },
    36             {
    37                 test: /.css$/,
    38                 use: [
    39                     'style-loader',
    40                     'css-loader'
    41                 ]
    42             },
    43             {
    44                 test: /.(png|jpe?g|gif|svg|woff2?|ttf|otf)(?.*)?$/,
    45                 loader: 'url-loader',
    46             },
    47             {
    48                 test: /.less$/,
    49                 use: [
    50                     'style-loader',
    51                     'css-loader',
    52                     'less-loader'
    53                 ]
    54             }
    55         ]
    56     },
    57     plugins: [
    58         new WebpackManifestPlugin(),
    59         new webpack.optimize.CommonsChunkPlugin({
    60             name: 'vendor',
    61             minChunks: function (module) {
    62                 // this assumes your vendor imports exist in the node_modules directory
    63                 return module.context && module.context.indexOf('node_modules') !== -1;
    64             }
    65         }),
    66         new webpack.optimize.CommonsChunkPlugin({
    67             name: 'common',
    68             chunks: ['qq', 'navi', 'log', 'guide', 'apply', 'voice', 'pianhang', 'dynamic'], //这里输入需要提取公共代码的entry
    69             minChunks: 2
    70         }),
    71         //CommonChunksPlugin will now extract all the common modules from vendor and main bundles
    72         new webpack.optimize.CommonsChunkPlugin({
    73             name: 'manifest', //But since there are no more common modules between them we end up with just the runtime code included in the manifest file
    74         }),
    75     ]
    76 }

    第16行代码可以参考这里这里,默认NPM包导出的是运行时构建,Vue2的运行时构建不支持单文件组件的template

    第58行的 WebpackManifestPlugin 作用是将输出文件名保存在文件中 (当输出文件名带 chunkhash 时很有用,参考这里)

    第59~74行的 CommonsChunkPlugin 作用是从打包后的 bundle 文件中提取公共模块,将 npm install 的公共模块和业务代码分开,这样浏览器就可以一直缓存公共模块的bundle,参考这里。第一个 CommonsChunkPlugin 作用是将 node_modules 里的模块提取到 vendor.js 里;第二个 CommonsChunkPlugin 作用是将 entry 里的公共代码提取出来放在 common.js 里,参考这里;第三个 CommonsChunkPlugin 作用是将 webpack 运行时代码放在 manifest.js 里

    webpack.config.dev.js

     1 "use strict"
     2 let webpack = require('webpack');
     3 let merge = require('webpack-merge');
     4 let base_config = require('./webpack.config.base');
     5 
     6 module.exports = merge(base_config, {
     7     entry: {
     8         qq: ['./src/qq/qq.js', 'webpack-hot-middleware/client'],
     9         navi: ['./src/navi/navi.js', 'webpack-hot-middleware/client'],
    10         log: ['./src/log/log.js', 'webpack-hot-middleware/client'],
    11         guide: ['./src/guide/guide.js', 'webpack-hot-middleware/client'],
    12         apply: ['./src/apply/apply.js', 'webpack-hot-middleware/client'],
    13         voice: ['./src/voice/voice.js', 'webpack-hot-middleware/client'],
    14         pianhang: ['./src/pianhang/pianhang.js', 'webpack-hot-middleware/client'],
    15         dynamic: ['./src/dynamic/dynamic.js', 'webpack-hot-middleware/client']
    16     },
    17     output: {
    18         filename: '[name].js',
    19     },
    20     devtool: '#eval-source-map',
    21     plugins: [
    22         new webpack.HotModuleReplacementPlugin(),
    23     ]
    24 });

    第 20 行设置source-map,方便用浏览器查看源代码

    webpack.config.prod.js

     1 "use strict"
     2 let webpack = require('webpack');
     3 let merge = require('webpack-merge');
     4 let base_config = require('./webpack.config.base');
     5 
     6 module.exports = merge(base_config, {
     7     entry: {
     8         qq: ['./src/qq/qq.js'],
     9         navi: ['./src/navi/navi.js'],
    10         log: ['./src/log/log.js'],
    11         guide: ['./src/guide/guide.js'],
    12         apply: ['./src/apply/apply.js'],
    13         voice: ['./src/voice/voice.js'],
    14         pianhang: ['./src/pianhang/pianhang.js'],
    15         dynamic: ['./src/dynamic/dynamic.js'],
    16     },
    17     output: {
    18         filename: '[name].[chunkhash].js',
    19     },
    20     plugins: [
    21         new webpack.optimize.UglifyJsPlugin()
    22     ]
    23 });

    第 21 行 UglifyJsPlugin 的作用是压缩、混淆代码

    webpack.config.analyze.js

     1 "use strict"
     2 
     3 let webpack = require('webpack');
     4 let merge = require('webpack-merge');
     5 var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
     6 let prod_config = require('./webpack.config.prod');
     7 
     8 module.exports = merge(prod_config, {
     9     plugins: [
    10         new BundleAnalyzerPlugin()
    11     ]
    12 });

    analyze 文件的作用利用 webpack-bundle-analyzer 插件分析打包情况,

    webpack --config ./config/webpack.config.analyze.js

    运行结果如下:

    webpack的配置文件自定义程度很高,所以在参考他人配置时最好能弄清楚为什么要这样写

    2. webpack-dev-server 

    在开发过程中另一个重要的东西是 webpack-dev-server,它的作用是当你改动源代码后能自动重新打包,再加上 webpack 的HMR-模块热替换特性,这样改动代码就能直接在浏览器里看到效果,省却了代码手动打包+刷新浏览器的步骤。使用 webpack-dev-server 有 CLI 和 API 两种使用方法。

    CLI 方式设置 dev 文件中的 HotModuleReplacementPlugin 和 devServer 启用 HMR。启动的命令为:

    webpack-dev-server --config ./config/webpack.config.dev.js

    API 方式直接在命令里设置参数,如:(这里用到了 Unix Domin Socket,也可以直接指定 ip和端口)

    webpack-dev-server --config config/webpack.dev.config.js --public 0.0.0.0:8056 --progress --inline --hot --socket .dev-shared/sockets/webpack.sock

    webpack-dev-server 的方式配置简单,缺点是引入 bundle 比较麻烦,需要指定其它端口

    3. webpack-dev-middleware 

    上述配置文件就是使用的该方法,需要有 koa-webpack-dev-middleware、koa-webpack-hot-middleware(热更新)。然后在 index.js 里写:

    1 if (process.env.NODE_ENV == 'dev') {
    2     let webpack = require('webpack');
    3     let webpackConfig = require('./config/webpack.config.dev.js');
    4     let webpackDevMiddleware = require('koa-webpack-dev-middleware');
    5     let webpackHotMiddleware = require('koa-webpack-hot-middleware');
    6     let compiler = webpack(webpackConfig);
    7     app.use(webpackDevMiddleware(compiler));
    8     app.use(webpackHotMiddleware(compiler));
    9 }

    这样就不需要通过额外的端口获取 bundle 文件了,注意这里是 koa 环境

    4. 如何在前端框架里引入 bundle

    由于 webpack prod 配置文件里使用了 chunkhash 作为 bundle 的名字的一部分,修改业务代码,chunkhash 会发生改变,所以需要通过一些方法自动将 bundle 名字注入到前端页面里:

    第一种方法是通过在后端 controller 里读取 manifest.json 里的内容,然后通过模板引擎,注入到页面里,例如 nunjucks:

    {% for path in paths %}
        <script src="{{path}}"></script>
    {% endfor %}

    第二种方法是拓展模板引擎命令,例如 xtpl:

    {{{ xScript('manifest.js') }}}
    {{{ xScript('vendor.js') }}}
    {{{ xScript('common.js') }}}
    {{{ xScript('apply.js') }}}

    xtpl 命令拓展示例 xtpl.ext.js :

     1 let xtplApp = require('xtpl/lib/koa');
     2 let xtpl = require('xtpl/lib/xtpl');
     3 let XTemplate = xtpl.XTemplate;
     4 
     5 XTemplate.addCommand('xScript', function(scope, option){
     6     let name = option.params[0];
     7     if (process.env.NODE_ENV !== 'dev') {
     8         let assets_map = require('./manifest');
     9         name = assets_map[name];
    10     }
    11     return '<script src="' + name + '" ></script>';
    12 });
    13 
    14 module.exports = xtplApp;

    然后在 index.js 里

    let xtpl = require('./extensions/xtpl.ext');

    注意引入 bundle 的时候要注意引入顺序:manifest > vendor > common > entry,否则可能会报 ReferenceError: webpackJsonp is not defined 错误,还要注意要有 .babelrc 文件:

    {
        "presets": ["es2015"]
    }

    否则会报 SyntaxError: Unexpected token: name (xxxxxx) from Uglify plugin 之类的错误,无法识别语言新特性

  • 相关阅读:
    接口和抽象类的区别联系(一)
    股指期货-基础知识
    A股魔咒
    .NET 分布式架构
    Spring Cloud Netflix
    现货、期货、期权、权证
    复盘-20190321
    复盘思考
    公司法
    2019年行情思考
  • 原文地址:https://www.cnblogs.com/cqq626/p/7140979.html
Copyright © 2020-2023  润新知