webpack打包相关

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

1.webpack 介绍

模块化思想:

  1. 按照代码的业务逻辑进行划分,分成一块一块,模块复用化,提高效率。
  2. 项目按照不同类型的文件,分别进行不同的管理

组件化思想:
组件化思想是对于不同的页面,使用不同的组件,从页面的角度考虑,是否有公共组件,实现组件复用,组件化。(vue、react)

webpack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等)、文件等,并将其转换和打包为合适的格式供浏览器使用。

2. webpack和Grunt和Gulp比较

Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而webpack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。

3.webpack核心概念

3.1 入口(entry)

入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
entry: {[entryChunkName: string]: string|Array<string>}

// 在多页应用中,(译注:每当页面跳转时)服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载
// 使用 CommonsChunkPlugin 为每个页面间的应用程序共享代码创建 bundle。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益
const config = {
  entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
};

3.2 输出(output)

配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置。

// 单个入口起点
const config = {
  output: {
    filename: 'bundle.js',
    path: '/home/proj/public/assets'
  }
};
// 多个入口起点
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }

3.3 loader

Loaders是webpack提供的最激动人心的功能之一了。通过使用不同的loader,webpack有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders可以把React的中用到的JSX文件转换为JS文件。
module.rules允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览,Loaders的配置包括以下几方面:

  • test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
  • loader:loader的名称(必须)
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
  • query:为loaders提供额外的设置选项(可选)

load的特性

  • loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何可能的操作。
  • loader 接收查询参数。用于对 loader 传递配置。
  • loader 也能够使用 options 对象进行配置。
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
  • 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。
    loader列表

3.4 插件(plugins)

插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。

  • 插件的使用
    要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)。
const webpack = require('webpack');
module.exports = {
...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究')
    ],
};
**1. HtmlWebpackPlugin插件**

这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。

npm install --save-dev html-webpack-plugin
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.html"//new 一个这个插件的实例,并传入相关的参数
        })
    ],
**2. Hot Module Replacement (HMR)热加载**

它允许你在修改组件代码后,自动刷新实时预览修改后的效果。
3. 其他插件
- OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
- UglifyJsPlugin:压缩JS代码;
- ExtractTextPlugin:分离CSS和JS文件
4. webpack打包速度优化

// 1.HotModuleReplacementPlugin 热加载模块使用
// 2.选择一个合适的devtool属性值 推荐:cheap-module-eval-source-map
// 3. 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件。
    // 自带的JS压缩插件是单线程执行的,而[webpack-parallel-uglify-plugin](https://github.com/gdborton/webpack-parallel-uglify-plugin)可以并行的执行
new ParallelUglifyPlugin({
           cacheDir: '.cache/',
           uglifyJS:{
             output: {
               comments: false
             },
             compress: {
               warnings: false
             }
           }
         })
// 4.CommonsChunkPlugin插件提取公共模块
      // 提取公共模块文件
        new webpack.optimize.CommonsChunkPlugin({
            chunks: ['home', 'detail'],
            // 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
            filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
            name: 'common'
        }),
    // 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
    // 文件入口配置
    entry: {
        home: './src/js/home',
        detail: './src/js/detail',
        // 提取jquery入公共文件
        common: ['jquery', 'react', 'react-dom']
    },

更多webpack打包速度优化参考

4. webpack使用

4.1 非配置文件命令行命令执行

# webpack非全局安装的情况
node_modules/.bin/webpack 入口文件 出口文件
#webpack 全局安装情况
webpack 入口文件 出口文件

webpack 的全局安装。

# 全局安装webpack
npm install webpack -g
# 将webpack安装到项目中
npm install webpack --save-dev

4.2 webpack配置文件使用

webpack的配置文件,使用vue-cli生成的

// webpack.config.js
module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    chunkFilename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  }
}

打包命令,可以使用npm相关配置,完成打包,再项目的pakage.json文件中,对scripts对象进行相关设置即可。

{
  "name": "tapp",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "scott",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src test/unit",
    "build": "node build/build.js" // 修改的是这里,JSON文件不支持注释,引用时请清除
  },
  "dependencies": {
    "axios": "^0.18.0",
    "babel-polyfill": "^6.26.0",
    "echarts": "^4.1.0",
  }
}

4.3 使用webpack构建本地服务器(devServer)

如何让你的浏览器监听你的代码的修改,并自动刷新显示修改后的结果------热加载
其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js(vue-cli使用的是express)构建,可以实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖。(vue-cli默认安装了依赖)

npm install --save-dev webpack-dev-server

webpack-dev-server的配置文件

  //  devServer服务器
  devServer: {
    clientLogLevel: 'warning', // LogLevel Possible values are none, error, warning or info (default). 日志级别
   // When using the HTML5 History API, the `index.html` page will likely have to be served in place of any `404` responses。替换404请求的页面
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true, // Enable webpack's Hot Module Replacement feature 热加载
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true, // Enable gzip compression for everything served 是否启用压缩
    host: HOST || config.dev.host, // url
    port: PORT || config.dev.port, // 端口
    open: config.dev.autoOpenBrowser, // 是否自动打开浏览器
    openPage: config.dev.openPage, // 打开浏览器的地址
    // 当存在编译器错误或警告时,在浏览器中显示全屏覆盖。默认情况下禁用
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    // 根路径
    publicPath: config.dev.assetsPublicPath,
    // 启用代URL
    proxy: {
     '/IntelligentWaterAffairs': {
        target: 'http://39.104.178.72:8080/', // 接口域名 //server
        changeOrigin: true, //是否跨域
      }
    },
    quiet: true, // necessary for FriendlyErrorsPlugin
    // 启用轮询
    watchOptions: {
      poll: config.dev.poll,
    }
  }

config/index.js 启用devtool

    /**
     * Source Maps
     */
    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',
    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,
    cssSourceMap: true

5. Babel

  • Babel是什么?
    Babel其实是一个编译JavaScript语言的平台。
  • Babel的目的是要达到那种效果?
    1. 让你能使用最新的JavaScript代码(ES6,ES7...),而不用管新标准是否被当前使用的浏览器完全支持;
    2. 让你能使用基于JavaScript进行了拓展的语言,比如Vue的JSX;
  • Babel是怎样配置的?
    babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。
  1. 安装babel
npm install --save-dev babel-loader babel-core babel-preset-env babel-plugin-transform-runtime babel-plugin-istanbul babel-polyfill babel-preset-stage-2 babel-register
  1. babelrc文件配置
{
  "presets": [
    ["env", { "modules": false }],
    "stage-2"
  ],
  "plugins": ["transform-runtime"],
  "comments": false,
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": [ "istanbul" ]
    }
  }
}

3.webpack.config.js 配置

      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },

参考资料: 部分内容来源于参考资料。
https://www.webpackjs.com/concepts/
https://segmentfault.com/a/1190000006178770#articleHeader5

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

推荐阅读更多精彩内容