如果你:

  • 是前端热爱者 :)
  • 有JavaScript/nodejs基础
  • 会使用一些常用命令行,mkdir,cd,etc.
  • 会使用npm
  • 想对webpack有更深的认识,或许此时你恰好遇到关于webpack的问题

那么,请继续阅读:

什么是webpack,为什么使用webpack

webpack官方是这样定义她的:

webpack 是一个用来构建我们应用程序中的 JavaScript 模块的工具。

简单来说就是一个打包器。(打包器: 它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。)

打包器茫茫多,那么为什么选择她呢?因为她具备以下特性

  • 附加模块按需加载
  • AMD define
  • AMD require / 按需加载
  • CommonJS exports
  • CommonJS require
  • CommonJS require.resolve
  • require 中拼接 require("./fi" + "le")
  • 调试支持 SourceUrl, SourceMaps
  • ES2015 import/export
  • require (guided) 中的表达式 require("./templates/" + template)
  • 生成单独包
  • 间接的 require: var r = require; r("./file")
  • 压缩 uglify
  • 可配置用 common bundle 构建多页
  • 可多个 bundle
  • Node.js 内置 libs require("path")
  • Node.js 的一些变量可用:process, __dir/filename, global
  • 丰富的插件
  • 预处理: loaders, transforms
  • 浏览器替换 web_modules, .web.js, package.json field, alias config option
  • 拥有文件系统: require 文件
  • 执行时(runtime)开销低:243B + 20B 每个模块 + 4B 每个依赖
  • 开发文件监听(watch)模式
  • etc.

用过的都说好。

如果你曾经挣扎于下面这些情况中的其中之一:

  • 不小心将一些不需要的样式表或者 JS 库引入生产环境,导致项目体积变大
  • 遇到作用域问题 - 不管是来自 CSS 还是 JavaScript
  • 不停寻找一个好的系统好让你可以在 JavaScript 代码里使用 Node 或 Bower 的模块,或者依赖一系列疯狂的后端配置来正确地使用那些模块
  • 需要优化资源分发机制却又担心会破坏掉某些东西

那么你就可以受益于 Webpack 了。它通过让 JavaScript 取代开发者的大脑来关心依赖和加载顺序,轻松地解决了上面这些问题。最好的部分是什么?Webpack 甚至可以在服务端无缝运行,这意味着你仍然可以使用 Webpack 来构建渐进式增强的网站。

安装

预准备

在开始前,先要确认你已经安装 Node.js 的最新版本。使用 Node.js 最新的 LTS 版本,是理想的起步。使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能或缺少相关 package 包。

本地安装

使用npm:

npm install --save-dev webpack
npm install --save-dev webpack@<version>
  • 当你在本地安装 webpack 后,你能够从node_modules/.bin/webpack 访问它的 bin 版本。

全局安装

npm install --global webpack

但不推荐这样做,原因是:会锁定 webpack 到指定版本,并且在使用不同的 webpack 版本的项目中可能会导致构建失败。

配置

很多情况,你在使用webpack中遇到的问题都是配置问题,好好阅读下下面的配置,90%的问题应该都可以解决了。

在根目录新建一个 webpack.config.js 文件用来声明 Webpack 的配置,你也可以指定特定的config文件:webpack --config mywebpack.config.js

const path = require('path');

module.exports = {
entry: "./app/entry", // string | object | array entry: ["./app/entry1", "./app/entry2"],
entry: {
a: "./app/entry-a",
b: ["./app/entry-b1", "./app/entry-b2"]
},
// 这里应用程序开始执行
// webpack 开始打包 output: {
// webpack 如何输出结果的相关选项 path: path.resolve(__dirname, "dist"), // string
// 所有输出文件的目标路径
// 必须是绝对路径(使用 Node.js 的 path 模块)
// PS:__dirname指的是根目录 filename: "bundle.js", // string filename: "[name].js", // 用于多个入口点(entry point)(出口点?)
filename: "[chunkhash].js", // 用于长效缓存
// 「入口分块(entry chunk)」的文件名模板(出口分块?) publicPath: "/assets/", // string publicPath: "",
publicPath: "https://cdn.example.com/",
// 输出解析文件的目录,url 相对于 HTML 页面 library: "MyLibrary", // string,
// 导出库(exported library)的名称 libraryTarget: "umd", // 通用模块定义 libraryTarget: "umd2", // 通用模块定义
libraryTarget: "commonjs2", // exported with module.exports
libraryTarget: "commonjs-module", // 使用 module.exports 导出
libraryTarget: "commonjs", // 作为 exports 的属性导出
libraryTarget: "amd", // 使用 AMD 定义方法来定义
libraryTarget: "this", // 在 this 上设置属性
libraryTarget: "var", // 变量定义于根作用域下
libraryTarget: "assign", // 盲分配(blind assignment)
libraryTarget: "window", // 在 window 对象上设置属性
libraryTarget: "global", // property set to global object
libraryTarget: "jsonp", // jsonp wrapper
// 导出库(exported library)的类型 /* 高级输出配置 */
pathinfo: true, // boolean
// 在生成代码时,引入相关的模块、导出、请求等有帮助的路径信息。 chunkFilename: "[id].js",
chunkFilename: "[chunkhash].js", // 长效缓存(/guides/caching)
// 「附加分块(additional chunk)」的文件名模板 jsonpFunction: "myWebpackJsonp", // string
// 用于加载分块的 JSONP 函数名 sourceMapFilename: "[file].map", // string
sourceMapFilename: "sourcemaps/[file].map", // string
// 「source map 位置」的文件名模板 devtoolModuleFilenameTemplate: "webpack:///[resource-path]", // string
// 「devtool 中模块」的文件名模板 devtoolFallbackModuleFilenameTemplate: "webpack:///[resource-path]?[hash]", // string
// 「devtool 中模块」的文件名模板(用于冲突) umdNamedDefine: true, // boolean
// 在 UMD 库中使用命名的 AMD 模块 crossOriginLoading: "use-credentials", // 枚举
crossOriginLoading: "anonymous",
crossOriginLoading: false,
// 指定运行时如何发出跨域请求问题 /* 专家级输出配置(自行承担风险) */
devtoolLineToLine: {
test: /\.jsx$/
},
// 为这些模块使用 1:1 映射 SourceMaps(快速) hotUpdateMainFilename: "[hash].hot-update.json", // string
// 「HMR 清单」的文件名模板 hotUpdateChunkFilename: "[id].[hash].hot-update.js", // string
// 「HMR 分块」的文件名模板 sourcePrefix: "\t", // string
// 包内前置式模块资源具有更好可读性
}, module: {
// 关于模块配置 rules: [
// 模块规则(配置 loader、解析器等选项) {
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo-files")
],
// 这里是匹配条件,每个选项都接收一个正则表达式或字符串
// test 和 include 具有相同的作用,都是必须匹配选项
// exclude 是必不匹配选项(优先于 test 和 include)
// 最佳实践:
// - 只在 test 和 文件名匹配 中使用正则表达式
// - 在 include 和 exclude 中使用绝对路径数组
// - 尽量避免 exclude,更倾向于使用 include issuer: { test, include, exclude },
// issuer 条件(导入源) enforce: "pre",
enforce: "post",
// 标识应用这些规则,即使规则覆盖(高级选项) loader: "babel-loader",
// 应该应用的 loader,它相对上下文解析
// 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的
// 查看 webpack 1 升级指南。 options: {
presets: ["es2015"]
},
// loader 的可选项
}, {
test: "\.html$" use: [
// 应用多个 loader 和选项
"htmllint-loader",
{
loader: "html-loader",
options: {
/* ... */
}
}
]
}, { oneOf: [ /* rules */ ] },
// 只使用这些嵌套规则之一 { rules: [ /* rules */ ] },
// 使用所有这些嵌套规则(合并可用条件) { resource: { and: [ /* 条件 */ ] } },
// 仅当所有条件都匹配时才匹配 { resource: { or: [ /* 条件 */ ] } },
{ resource: [ /* 条件 */ ] },
// 任意条件匹配时匹配(默认为数组) { resource: { not: /* 条件 */ } }
// 条件不匹配时匹配
], /* 高级模块配置 */
noParse: [
/special-library\.js$/
],
// 不解析这里的模块 unknownContextRequest: ".",
unknownContextRecursive: true,
unknownContextRegExp: /^\.\/.*$/,
unknownContextCritical: true,
exprContextRequest: ".",
exprContextRegExp: /^\.\/.*$/,
exprContextRecursive: true,
exprContextCritical: true,
wrappedContextRegExp: /.*/,
wrappedContextRecursive: true,
wrappedContextCritical: false,
// specifies default behavior for dynamic requests
}, resolve: {
// 解析模块请求的选项
// (不适用于对 loader 解析) modules: [
"node_modules",
path.resolve(__dirname, "app")
],
// 用于查找模块的目录 extensions: [".js", ".json", ".jsx", ".css"],
// 使用的扩展名 alias: {
// 模块别名列表 "module": "new-module",
// 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file" "only-module$": "new-module",
// 起别名 "only-module" -> "new-module",但不匹配 "module/path/file" -> "new-module/path/file" "module": path.resolve(__dirname, "app/third/module.js"),
// 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误
// 模块别名相对于当前上下文导入
},
/* 可供选择的别名语法 */ alias: [
{
name: "module",
// 旧的请求 alias: "new-module",
// 新的请求 onlyModule: true
// 如果为 true,只有 "module" 是别名
// 如果为 false,"module/inner/path" 也是别名
}
], /* 高级解析选项 */
symlinks: true,
// 遵循符号链接(symlinks)到新位置 descriptionFiles: ["package.json"],
// 从 package 描述中读取的文件 mainFields: ["main"],
// 从描述文件中读取的属性
// 当请求文件夹时 aliasFields: ["browser"],
// 从描述文件中读取的属性
// 以对此 package 的请求起别名 enforceExtension: false,
// 如果为 true,请求必不包括扩展名
// 如果为 false,请求可以包括扩展名 moduleExtensions: ["-module"],
enforceModuleExtension: false,
// 类似 extensions/enforceExtension,但是用模块名替换文件 unsafeCache: true,
unsafeCache: {},
// 为解析的请求启用缓存
// 这是不安全,因为文件夹结构可能会改动
// 但是性能改善是很大的 cachePredicate: (path, request) => true,
// predicate function which selects requests for caching plugins: [
// ...
]
// 应用于解析器的附加插件
}, performance: {
hints: "warning", // 枚举 hints: "error", // 性能提示中抛出错误
hints: false, // 关闭性能提示
maxAssetSize: 200000, // 整数类型(以字节为单位)
maxEntrypointSize: 400000, // 整数类型(以字节为单位)
assetFilter: function(assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
}, devtool: "source-map", // enum devtool: "inline-source-map", // 嵌入到源文件中
devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中
devtool: "hidden-source-map", // SourceMap 不在源文件中引用
devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant)
devtool: "cheap-module-source-map", // 有模块映射(module mappings)的 SourceMap 低级变体
devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。
// 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
// 牺牲了构建速度的 `source-map' 是最详细的。 context: __dirname, // string(绝对路径!)
// webpack 的主目录
// entry 和 module.rules.loader 选项
// 相对于此目录解析 target: "web", // 枚举 target: "webworker", // WebWorker
target: "node", // node.js 通过 require
target: "async-node", // Node.js 通过 fs and vm
target: "node-webkit", // nw.js
target: "electron-main", // electron,主进程(main process)
target: "electron-renderer", // electron,渲染进程(renderer process)
target: (compiler) => { /* ... */ }, // 自定义
// 包(bundle)应该运行的环境
// 更改 块加载行为(chunk loading behavior) 和 可用模块(available module) externals: ["react", /^@angular\//], externals: "react", // string(精确匹配)
externals: /^[a-z\-]+($|\/)/, // 正则
externals: { // 对象
angular: "this angular", // this["angular"]
react: { // UMD
commonjs: "react",
commonjs2: "react",
amd: "react",
root: "React"
}
},
externals: (request) => { /* ... */ return "commonjs " + request }
// 不要遵循/打包这些模块,而是在运行时从环境中请求他们 stats: "errors-only", stats: { //object
assets: true,
colors: true,
errors: true,
errorDetails: true,
hash: true,
// ...
},
// 精确控制要显示的 bundle 信息 devServer: {
proxy: { // proxy URLs to backend development server
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
compress: true, // enable gzip compression
historyApiFallback: true, // true for index.html upon 404, object for multiple paths
hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
https: false, // true for self-signed, object for cert authority
noInfo: true, // only errors & warns on hot reload
// ...
}, plugins: [
// ...
],
// 附加插件列表 /* 高级配置 */
resolveLoader: { /* 等同于 resolve */ }
// 独立解析选项的 loader profile: true, // boolean
// 捕获时机信息 bail: true, //boolean
// 在第一个错误出错时抛出,而不是无视错误。 cache: false, // boolean
// 禁用/启用缓存 watch: true, // boolean
// 启用观察 watchOptions: {
aggregateTimeout: 1000, // in ms
// 将多个更改聚合到单个重构建(rebuild) poll: true,
poll: 500, // 间隔单位 ms
// 启用轮询观察模式
// 必须用在不通知更改的文件系统中
// 即 nfs shares(译者注:Network FileSystem,最大的功能就是可以透過網路,讓不同的機器、不同的作業系統、可以彼此分享個別的檔案 ( share file ))
}, node: {
/* TODO */
}, recordsPath: path.resolve(__dirname, "build/records.json"),
recordsInputPath: path.resolve(__dirname, "build/records.json"),
recordsOutputPath: path.resolve(__dirname, "build/records.json"),// TODO}

分割代码(代码分离)

代码分离是 webpack 中最引人注目的特性之一。你可以把你的代码分离到不同的 bundle 中,然后你就可以去按需加载这些文件

  • 例如,当用户导航到匹配的路由,或用户触发了事件时,加载对应文件。如果使用了正确的使用方式,这可以使我们有更小的 bundle,同时可以控制资源加载优先级,从而对你的应用程序加载时间产生重要影响。

总的来说,使用 webpack 可以完成两类代码分离工作:

按资源进行分离

一、分离第三方库

现代流行开发网站,多多少少都用到了不少三方库,而这些三方库一般不会频繁的去修改,将这些代码和我们的业务逻辑一同打包,这无疑是低效的。如果我们将这些库(library)中的代码,保留在与应用程序代码相独立的 bundle 中,我们就可以利用浏览器缓存机制,把这些文件长时间地缓存在用户机器上,增加了访问速度。

为了完成这个目标,不管应用程序代码如何变化,vendor 文件名中的 hash 部分必须保持不变。学习如何使用 CommonsChunkPlugin 分离 vendor/library 代码。

你可能会想到搞多个入口啊,类似这样:

var path = require('path');

module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
}
}

再次运行 webpack,可以发现生成了两个 bundle。然而如果查看他们的代码,会发现 moment 的代码在两个文件中都出现了!其原因是 moment 是主应用程序(例如 index.js)的依赖模块,每个入口起点都会打包自己的依赖模块。

为此我们需要使用插件CommonsChunkPlugin,这是一个非常复杂的插件。它从根本上允许我们从不同的 bundle 中提取所有的公共模块,并且将他们加入公共 bundle 中。如果公共 bundle 不存在,那么它将会创建一个出来。

var webpack = require('webpack');
var path = require('path'); module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor' // 指定公共 bundle 的名字。
})
]
}
}

但是这样vendor的文件的hashcode还是会每个编译都不一样,为此,可以使用manifest,如下:

var webpack = require('webpack');
var path = require('path'); module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest'] // 指定公共 bundle 的名字。
})
]
}
};

总结使用CommonsChunkPlugin:

var webpack = require('webpack');
var path = require('path'); module.exports = function() {
return {
entry: {
main: './index.js' //Notice that we do not have an explicit vendor entry here
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// this assumes your vendor imports exist in the node_modules directory
return module.context && module.context.indexOf('node_modules') !== -1;
}
}),
//CommonChunksPlugin will now extract all the common modules from vendor and main bundles
new webpack.optimize.CommonsChunkPlugin({
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
})
]
};
}

你还可以使用DllPlugin(提供分离打包的方式,可以极大提高构建时间性能)

new webpack.DllPlugin({
path: `${__dirname}/manifest.json`,
name: '[name]',
context: __dirname,
})

二、分离CSS

为了用 webpack 对 CSS 文件进行打包,你可以像其它模块一样将 CSS 引入到你的 JavaScript 代码中,同时用 css-loader (像 JS 模块一样输出 CSS),也可以选择使用 ExtractTextWebpackPlugin (将打好包的 CSS 提出出来并输出成 CSS 文件)。

为什么会使用这个插件,假如不使用,那么你可能如下:

安装CSS加载器:

npm install --save-dev css-loader style-loader

webpack配置:

module.exports = {
module: {
rules: [{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}]
}
}

但是这样,CSS 会跟你的 JavaScript 打包在一起,并且在初始加载后,通过一个 <style> 标签注入样式,然后作用于页面。

这里有一个缺点就是,你无法使用浏览器的能力,去异步且并行去加载 CSS。取而代之的是,你的页面需要等待整个 JavaScript 文件加载完,才能进行样式渲染。

webpack 能够用 ExtractTextWebpackPlugin 帮助你将 CSS 单独打包,以解决以上问题。

安装:

npm install --save-dev extract-text-webpack-plugin

添加到配置中使用她:

+var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [{
test: /\.css$/,
- use: [ 'style-loader', 'css-loader' ]
+ use: ExtractTextPlugin.extract({
+ use: 'css-loader'
+ })
}]
},
+ plugins: [
+ new ExtractTextPlugin('styles.css'),
+ ]
}

OK,CSS分离完成。

按工程需求进行分离

工程一旦达到一定的程度,就会有按需加载的需求。接下来是说如何将您的 bundle 拆分成可以在之后异步下载的 chunk。例如,这允许首先提供最低限度的引导 bundle,并在稍后再异步地加载其他功能。如果你们不需要按需加载,那么可以跳过。

webpack 支持两种相似的技术实现此目的:使用 import() (推荐,ECMAScript 提案) 和 require.ensure() (遗留,webpack 特定,这里不讨论这个,舍弃)。

import()

ES2015 loader 规范定义了 import() 作为一种在运行时(runtime)动态载入 ES2015 模块的方法。

webpack 把 import() 作为一个分离点(split-point),并把引入的模块作为一个单独的 chunk。 import() 将模块名字作为参数并返回一个 Promoise 对象,即 import(name) -> Promise.

如:

function determineDate() {
import('moment').then(function(moment) {
console.log(moment().format());
}).catch(function(err) {
console.log('Failed to load moment', err);
});
} determineDate();
  • 注意,由于 webpack 至少需要感知到文件的位置信息,因此类似 import(foo)完全动态语句会导致失败。这是因为 foo 可以是系统或项目中的任意路径下任意文件。import() 至少应感知的信息是模块所处的位置,所以打包将限制在特定目录或一组文件中。

例如,import(``./locale/${language}.json``) 将会使 ./locale 目录下的每个 .json 都打包到分离点(split-point)中。在运行时(runtime),当计算出变量 language 时,任何像 english.jsongerman.json 这样的文件都可以供使用。所以请牢记,在使用 import() 时,该路径必须包含路径信息或完整的静态路径(就像上面例子中的 'moment' 一样)。

使用Promise polyfill

使用它是因为:import() 在内部依赖于 Promise。 如果你想在老版本浏览器使用 import(),请记得使用 polyfill(例如 es6-promise 或 promise-polyfill)来 shim Promise。

入口处配置:

import Es6Promise from 'es6-promise';
Es6Promise.polyfill();
// 或
import 'es6-promise/auto';
// 或
import Promise from 'promise-polyfill';
if (!window.Promise) {
window.Promise = Promise;
}

自定义Chunk 名称

这个是webpack 2.4.0新加的"魔力注释"

import(/* webpackChunkName: "my-chunk-name" */ 'module');

配合 Babel 使用

import() 是属于 Stage 3 的特性,需要安装/添加 syntax-dynamic-import 插件来避免 parser 报错。

npm install --save-dev babel-core babel-loader babel-plugin-syntax-dynamic-import babel-preset-es2015

然后你就可以使用了:

function determineDate() {
import('moment')
.then(moment => moment().format('LLLL'))
.then(str => console.log(str))
.catch(err => console.log('Failed to load moment', err));
} determineDate();

但是你的webpack的配置文件得像下面这样去修改它:

module.exports = {
entry: './index-es2015.js',
output: {
filename: 'dist.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
options: {
presets: [['es2015', {modules: false}]],
plugins: ['syntax-dynamic-import']
}
}]
}]
}
};

没有使用 syntax-dynamic-import 插件会导致构建失败,并提示:

  • Module build failed(模块构建失败): SyntaxError: 'import' and 'export' may only appear at the top level('import' 和 'export' 只能出现在顶层),或提示
  • Module build failed(模块构建失败): SyntaxError: Unexpected token, expected {

使用async/await

说了,import(name) -> Promise返回的是promise,so,用async/await大法好;那么如何使用呢:

安装插件:

npm install --save-dev babel-plugin-transform-async-to-generator babel-plugin-transform-regenerator babel-plugin-transform-runtime

然后你就可以这样用了:

async function determineDate() {
const moment = await import('moment');
return moment().format('LLLL');
} determineDate().then(str => console.log(str));

当然在插件是这样使用的:

module.exports = {
entry: './index-es2017.js',
output: {
filename: 'dist.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
options: {
presets: [['es2015', {modules: false}]],
plugins: [
'syntax-dynamic-import',
'transform-async-to-generator',
'transform-regenerator',
'transform-runtime'
]
}
}]
}]
}
};

import() 导入整个模块命名空间

需要注意的是import() 导入整个模块命名空间。举个例子:

// 示例 1: 最顶层 import
import * as Component from './component';
// 示例 2: 使用 import() 进行代码分离
import('./component').then(Component => /* ... */);

但是,在使用带有 ES2015 模块的 import() 时,您必须显式地访问默认导出和命名导出:

async function main() {
// 解构赋值用法示例
const { default: Component } = await import('./component');
// 行内用法示例
render((await import('./component')).default);
} 可去我博客主页查看更多详情:http://www.fangyongle.com/xiang-xi-webpack-2jiao-cheng/

【webpack整理】一、安装、配置、按需加载的更多相关文章

  1. vue项目引用 iView 组件——全局安装与按需加载

    框架的热度,出现了不少基于Vue的UI组件库,这次项目用到了 iView 这个组件库.使用方法官网很详细. 官网:https://www.iviewui.com/ 这篇文章主要是记录一下npm 全局安 ...

  2. Vue + WebPack + Typescript初学者VSCode项目 (按需加载、跨域调试、await/async)

    万事开头难,一个好的Hello World程序可以节省我们好多的学习时间,帮助我们快速入门.Hello World程序之所以是入门必读必会,就是因为其代码量少,简单易懂.但我觉得,还应该做到功能丰富, ...

  3. webpack:代码分割与按需加载

    代码分割就是我们根据实际业务需求将代码进行分割,然后在合适的时候在将其加载进入文档中. 代码中总有些东西我们希望拆分开来,比如: 使用概率较低的模块,希望后期使用的时候异步加载 框架代码,希望能利用浏 ...

  4. webpack css模块化和ant-design按需加载冲突

    其实具体出现了什么问题,我也记得不清楚了,今天突然回想起来必须记录一下,一个思想就是用exclude将node_module目录下的文件排除,网上有很多相关例子,但不知是不是因为时间久远,都不生效,无 ...

  5. router 配置按需加载对应的组件,配置active

    const routes = [ { path: '/', component: App, children: [ {path: '/index/:type', name: 'index', comp ...

  6. react-router v4 按需加载的配置方法

    在react项目开发中,当访问默认页面时会一次性请求所有的js资源,这会大大影响页面的加载速度和用户体验.所以添加按需加载功能是必要的,以下是配置按需加载的方法: 安装bundle-loader np ...

  7. 快速搭建react项目骨架(按需加载、redux、axios、项目级目录等等)

    一.前言 最近整理了一下项目骨架,顺便自定义了一个脚手架,方便日后使用.我会从头开始,步骤一步步写明白,如果还有不清楚的可以评论区留言.先大致介绍一下这个骨架,我们采用 create-react-ap ...

  8. react-antd 按需加载报错

    基于create-react-app 搭建的 react 项目 引入  antd UI  配置按需加载 但是报一下错误 .翻译过了一下 是内嵌JavaScript选项没有开启什么的 大白话就是 les ...

  9. 基于create-react-app脚手架,按需加载antd组件以及less样式

    摘要 为了更好的书写css样式,在react中引入less,在网上查询了许多关于react引入less样式文件的资料,大多数都是需要在react项目中npm run eject暴露出底层文件,然后在底 ...

随机推荐

  1. Hibernate考试试题(部分题库)含答案

    Hibernate考试试题 (题库) 1.  在Hibernate中,下列说法正确的有( ABC ).[选三项] A.Hibernate是一个开放源代码的对象关系映射框架 B.Hibernate对JD ...

  2. [ext4] 磁盘布局 - extent tree

    传统的类Unix文件系统,比如Ext3,都是使用一个间接数据块映射表来记录每一个数据块的分配情况的.但是这种机制对于超大文件的存储是有缺陷的,特别是当对超大文件进行删除和截断操作时.映射表会对每一个数 ...

  3. [进程管理] 理解 Linux 的处理器负载均值

    原文链接: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages http://www.gracecode. ...

  4. ASP.Net零碎

    ASP.Net零碎 ServerPush 什么是ServerPush,服务器向客户端浏览器“推送”,其实就是“长连接”. 只有浏览器请求服务器端,服务器端才有给浏览器响应数据,不会主动向浏览器推送数据 ...

  5. iOS APP打包分发给远程的手机测试

    APP要打包给远程的朋友或客户测试,但又不是企业账号的情况下,我们只能根据手机的udid进行描述证书的配置,再打包分发给提供了udid的手机进行安装 一.如何得到udid? 手机连接到mac电脑,打开 ...

  6. SpringMVC 国际化-中英文切换

    项目结构 1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http: ...

  7. SQLServer中使用扩展事件获取Session级别的等待信息以及SQLServer 2016中Session级别等待信息的增强

    本文出处:http://www.cnblogs.com/wy123/p/6835939.html 什么是等待 简单说明一下什么是等待:当应用程序对SQL Server发起一个Session请求的时候, ...

  8. ubuntu16.04 编译运行 LSD-SLAM

    下载编译LSDSLAM,可能会出现 CreateGlutWindowAndWind is not a member of pangolin 以及 该函数参数报错的问题: 原因是在新的pangolin版 ...

  9. 学习笔记:HTML+CSS 基础知识

    1.<q>标签,短文本引用       <q>引用文本</q> <q>标签的真正关键点不是它的默认样式双引号(如果这样我们不如自己在键盘上输入双引号就行 ...

  10. 无分类编址(CIDR)构成超网

    CIDR(无分类域间路由选择) CIDR最主要有两个以下特点: 消除传统的A,B,C地址和划分子网的概念,更有效的分配IPv4的地址空间,CIDR使IP地址又回到无分类的两级编码.记法:IP地址::= ...