共计 11405 个字符,预计需要花费 29 分钟才能阅读完成。
一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 Webpack 是什么 |
四 Webpack 外围概念 |
五 Webpack 构建流程 |
六 entry |
七 output |
八 loader |
8.1 对于文件解决常见的 loader |
8.2 对于语法查看常见 loader |
8.3 对于 HTML 代码解决常见的 loader |
8.4 对于 CSS 代码解决常见的 loader |
8.5 对于 JS 代码解决常见的 loader |
九 plugin |
9.1 常见 plugin |
9.2 提高效率的 plugin |
十 loader 和 plugin 的区别 |
十一 resolve |
十二 从 0 开始配置 Webpack |
12.1 技术选型 |
12.2 Loader 配置 – 解决 CSS、Less |
12.3 Loader 配置 – 解决图片 |
12.4 Loader 配置 – 解决字体 |
12.5 Loader 配置 – MPA 多页面打包通用计划 |
12.6 SourceMap |
12.7 WebpackDevServer |
12.8 babel 解析 |
12.9 React |
12.10 性能优化 |
12.11 其余 |
十三 常识补充:懒加载 |
13.1 代码宰割 |
13.2 实现原理 |
13.3 Vue 按需加载 |
十四 常识补充:热更新 |
14.1 开启热更新 |
14.2 热更新原理 |
十五 常识补充:3 种 hash |
十六 常识补充:source map |
十七 常识补充:Webpack 打包原理 |
十八 参考文献 |
18.1 Webpack 系列文章 |
18.2 Webpack 性能优化 |
18.3 Scope Hoisting |
18.4 Tree Shaking |
18.5 懒加载 |
二 前言
返回目录
都 2020 了,不会点 Webpack 如同有点说不过去。
然而事实上如果不是调配到【架构组】之类的个人中,感觉接触 Webpack 的概率会少点吧。
就好比 jsliang 在上家公司,就没机会接触 Webpack,都是用这他人曾经配置好的计划,纯正做一个业务仔~
三 Webpack 是什么
返回目录
Webpack 是一个古代 JavaScript 应用程序的动态模块打包器(module bundler
)。
当 Webpack 解决应用程序时,它会递归地构建一个依赖关系图(dependency graph
),其中蕴含应用程序须要的每个模块,而后将所有这些模块打包成一个或多个 bundle
。
所以,它的实质是一个模块打包器,其工作是将每个模块打包成相应的 bundle
。
四 Webpack 外围概念
返回目录
mode
:模式。对应有开发模式、生产模式等entry
:入口output
:进口loader
:模块转换器,用于把模块原内容依照需要转换成新内容。Webpack 对于.jpg
、.txt
等内容无奈解决,就须要file-loader
、url-loader
等进行帮助解决。plugins
:扩大插件,在 Webpack 构建流程中的特定机会注入拓展逻辑来扭转构建后果或者做其余你想做的事件。
五 Webpack 构建流程
返回目录
Webpack 就像一条生产线,要通过一系列解决流程后能力将源文件转换成输入后果。
这条生产线上的每个解决流程的职责都是繁多的,多个流程之间有存在依赖关系,只有实现以后解决后能力交给下一个流程去解决。
Webpack
的运行流程是一个串行的过程,从启动到完结会顺次执行以下流程:
- 初始化参数 :从配置文件和
Shell
语句中读取与合并参数,得出最终的参数 - 开始编译 :用上一步失去的参数初始化
Compiler
对象,加载所有配置的插件,执行对象的run
办法开始执行编译 - 确定入口 :依据配置中的
entry
找出所有的入口文件 - 编译模块 :从入口文件登程,调用所有配置的
Loader
对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都通过了本步骤的解决 - 实现模块编译 :在通过第 4 步应用
Loader
翻译完所有模块后,失去了每个模块被翻译后的最终内容以及它们之间的依赖关系 - 输入资源 :依据入口和模块之间的依赖关系,组装成一个个蕴含多个模块的
Chunk
,再把每个Chunk
转换成一个独自的文件退出到输入列表,这步是能够批改输入内容的最初机会 - 输入实现 :在确定好输入内容后,依据配置确定输入的门路和文件名,把文件内容写入到文件系统
简略来说:
- 初始化 :启动构建,读取与合并配置参数,加载
Plugin
,实例化Compiler
(钩子) - 编译 :从
Entry
登程,针对每个Module
(模块)串行调用对应的Loader
去翻译文件的内容,再找到该Module
依赖的Module
,递归地进行编译解决 - 输入 :将编译后的
Module
组合成Chunk
,将Chunk
转换成文件,输入到文件系统中(Chunk
就是打包过程中,入口模块援用其余模块,模块再援用模块,这个关系链连贯的Module
就造成了Chunk
)
在这个过程中,Webpack
会在特定的工夫点播送出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件能够调用 Webpack
提供的 API
扭转 Webpack
的运行后果。
六 entry
返回目录
指定打包⼊口文件,有三种不同的模式:string | object | array
。
一对一:一个入口、一个打包文件
module.exports = {entry: './src/index.js'}
多对一:多个入口、一个打包文件
module.exports = {
entry: [
'./src/index1.js',
'./src/index2.js',
]
}
多对多:多个入口、多打包文件
module.exports = {
entry: {
'index1': "./src/index1.js",
'index2': "./src/index2.js"
}
}
七 output
返回目录
打包后的文件地位。
module.exports = {
...,
output: {path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
filename: "[name].js"
}
}
- 能够指定一个固定的文件名称,如果是多入口多进口(
entry
为对象),则不能应用单文件进口,须要应用上面的形式 - 通过
Webpack
内置的变量占位符:[name]
八 loader
返回目录
loader
的执行程序是从右向左执行的,也就是前面的 loader
先执行。
如果有配置:
// webpack.config.js
module.exports = {
//...
module: {
rules: [
{test: /\.(le|c)ss$/,
use: ['style-loader', 'css-loader', 'less-loader'],
exclude: /node_modules/,
},
],
},
};
那就是先解决 less-loader
,再解决 css-loader
,最初解决 style-loader
。
8.1 对于文件解决常见的 loader
返回目录
file-loader
:当引入的文件是.png
、.txt
等时,能够通过file-loader
解析我的项目中的url
引入。依据配置将文件拷贝到相应的门路,并批改打包后文件的引入门路,让它指向正确的文件。url-loader
:url-loader
封装了file-loader
且能够不依赖于file-loader
独自应用,并且能够配置limit
。对小于limit
大小的图片转换成Base64
,大于limit
的时候应用file-loader
里的办法。
8.2 对于语法查看常见 loader
返回目录
tslint-loader
:通过 TSLint 查看 TypeScript 代码eslint-loader
:通过 ESLint 查看 JavaScript 代码
8.3 对于 HTML 代码解决常见的 loader
返回目录
html-withimg-loader
:解决 HTML 中的图片
8.4 对于 CSS 代码解决常见的 loader
返回目录
style-loader
:动态创建style
标签,将 CSS 代码插入到head
中。css-loader
:负责解决@import
、url
等语句。例如import css from 'file.css'
、url(image.png)
。postcss-loader
:负责进一步解决 CSS 文件,比方增加浏览器前缀,压缩 CSS 等。less-loader
:将.less
文件内容转换成 CSS。sass-loader
:将.sass
文件内容转换成 CSS。
8.5 对于 JS 代码解决常见的 loader
返回目录
babel-loader
:将 JS 代码向低版本转换,咱们须要应用babel-loader
。ts-loader
:将 TypeScript 转换成 JavaScript
九 plugin
返回目录
9.1 常见 plugin
返回目录
clean-webpack-plugin
:打包前主动清理dist
目录,避免文件残留。copy-webpack-plugin
:将单个文件或者整个目录复制到构建目录mini-css-extract-plugin
:将 CSS 抽离进去独自打包并且通过配置能够设置是否压缩。html-webpack-plugin
:这个插件能够配置生成一个 HTML5 文件,其中script
标签蕴含所有 Webpack 包。如果你设置多个入口点,你能够据此实现多页面利用打包。
9.2 提高效率的 plugin
返回目录
webpack-dashboard
:能够更敌对的展现相干打包信息。webpack-merge
:提取公共配置,缩小反复配置代码speed-measure-webpack-plugin
:简称 SMP,剖析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈。size-plugin
:监控资源体积变动,尽早发现问题HotModuleReplacementPlugin
:模块热替换
十 loader 和 plugin 的区别
返回目录
Loader
Loader
实质上就是一个函数,对接管到的内容进行转换,返回转换后的后果。
因为 Webpack
只意识 JavaScript,所以 Loader
就成了翻译官,对不同类型的资源进行解决。
就好比 file-loader
或者 url-loader
,配置之后就能够正确援用 png
等格局的图片、txt
等格式文件。
又好比 style-loader
以及 css-loader
,援用后就能够对 CSS 内容进行预编译解决。
Plugin
Plugin
就是插件,就好比 jsliang 编写的 VS Code 插件一样,Plugin
拓展了 Webpack
的性能。
Plugin
就是在 Webpack
的生命周期中进行各种操作,从而达到使用者目标插件。
就好比 html-webpack-plugin
,配合多入口模式应用之后,就能够实现多页面利用的性能。
又好比 clean-webpack-plugin
实现打包之前清空 dist
目录,copy-webpack-plugin
能够将单个文件或者整个目录复制到构建目录。
十一 resolve
返回目录
resolve
配置 Webpack 如何寻找模块所对应的文件。
Webpack 内置 JavaScript 模块化语法解析性能,默认会采纳模块化规范里约定好的规定去寻找,但你能够依据本人的须要批改默认的规定。
// webpack.config.js
module.exports = {
//....
resolve: {modules: ['./src/components', 'node_modules'] // 从左到右顺次查找
}
}
resolve.modules
:配置 Webpack 去哪些目录下寻找第三方模块,默认状况下,只会去node_modules
下寻找,如果你在我的项目中某个文件夹下的模块常常被导入,不心愿写很长的门路,那么就能够通过配置resolve.modules
来简化。resolve.alias
:配置项通过别名把原导入门路映射成一个新的导入门路。resolve.extensions
:适配多端的我的项目中,可能会呈现.web.js
,.wx.js
,例如在转 Web 的我的项目中,咱们心愿首先找.web.js
,如果没有,再找.js
。extensions: ['web.js', '.js']
。
十二 从 0 开始配置 Webpack
返回目录
如何从 0 开始配置一个属于本人的 Webpack 脚手架呢?那就波及到选型问题。
12.1 技术选型
返回目录
- 挪动端 || PC
- MPA || SPA
- HTML || 模板引擎
- CSS || 预处理器
- JavaScript ES5 || ES6
- 本地公布服务(数据模仿)
- React || Vue
- 多人我的项目 || 单人我的项目
- 语法标准 Eslint
- 单元测试
- 提交标准
12.2 Loader 配置 – 解决 CSS、Less
返回目录
- use:
['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
less less-loader
:解析.less
文件postcss-loader autoprefixer
:对flex
布局等进行前缀补充
12.3 Loader 配置 – 解决图片
返回目录
file-loader
:解析.txt
、.png
、.md
等格式文件url-loader
:limit: 1024
,判断大小是否解决成base64
格局
12.4 Loader 配置 – 解决字体
返回目录
url-loader
12.5 Loader 配置 – MPA 多页面打包通用计划
返回目录
- 装置
glob
- 将
entry
和htmlwebpackplugin
动静生成
12.6 SourceMap
返回目录
- 开发环境配置:
devtool: "cheap-module-eval-source-map
- 线上生成配置(不举荐):
devtool: "cheap-module-source-map"
12.7 WebpackDevServer
返回目录
- 装置
- 配置:
devServer
HMR
(热模块替换,Hot Module Replacement)- 开启 JS 模块的
HMR
,须要Webpack
配合
12.8 babel 解析
返回目录
-
装置:
npm i babel-loader @babel/core @babel-preset-env -D
@babel/core
:babel
外围babel-loader
:babel
和Webpack
的连贯桥梁babel-preset-env
:输入什么样的代码,用它来解决
babel-loader
:解析 ES6+@babel/polyfill
:垫片。蕴含所有 ES6+ 新个性代码.babelrc
12.9 React
返回目录
- 装置:
react react-dom
- 应用:
@babel/preset-react
12.10 性能优化
返回目录
- 放大
loader
的文件范畴:loader
的include
配置,能够指定src
目录,缩小查看范畴。 - 优化
resolve.modules
配置:配置Webpack
去哪些目录下寻找第三方模块,默认node_modules
。 - 拆散 CSS:
MiniCssExtractPlugin
-
hash
、chunkhash
、contenthash
区别hash
作用域 JS、CSS,图片的hash
有区别,每次打包构建都会变动一次。chunkhash
以chunk
为单位,批改了那局部就改变哪局部的hash
。(同时依赖的模块也会扭转hash
)contenthash
只有本人内容产生扭转,才产生扭转(区别于chunkhash
。- 所以 JS 实用于
chunkhash
;CSS 实用于contenthash
;Image 实用于hash
- 压缩 CSS:
optimize-css-assets-webpack-plugin
和cssnano
- 压缩 HTML:
html-webpack-plugin
- 压缩图片:
img-webpack-loader
- 拆散
Webpack
配置:拆散base.config
、dev.config
、mpa.config
和pro.config
4 个,通过merge
进行config
配置的合并
更多看这里:
Webpack 性能优化
12.11 其余
返回目录
- 如何简略编写一个
Webpack
解析器 - 如何编写一个
Webpack loader
- 如何编写一个
Webpack plugin
十三 常识补充:懒加载
返回目录
懒加载或者按需加载,是一种很好的优化网页或利用的形式。
这种形式实际上是先把你的代码在一些逻辑断点处罚来到,而后在一些代码块中实现某些操作后,立刻援用或行将援用另外一些新的代码块。
这样放慢了利用的初始加载速度,加重了它的总体体积,因为某些代码块可能永远不会被加载。
13.1 代码宰割
返回目录
代码宰割(code splitting
)是指:将脚本中无需立刻调用的代码在代码构建时转变为异步加载的过程。
在 Webpack 构建时,会防止加载已申明要异步加载的代码,异步代码会被独自拆散出一个文件,当代码理论调用时被加载至页面。
代码宰割技术的外围是 异步加载资源 。
可喜的是,浏览器容许咱们这么做,W3C stage 3
标准:whatwg/loader 对其进行了定义:你能够通过 import()
关键字让浏览器在程序执行时异步加载相干资源。
在 Vue 中,能够间接应用 import()
关键字做到这一点,而在 React 中,你须要应用 react-loadable
去实现同样的事。
13.2 实现原理
返回目录
- 将须要进行懒加载的子模块独自打包成文件(
children chunk
) - 借助函数来实现提早进行子模块的加载代码(
import
)
print.js
console.log('输入 1');
export default () => {console.log('输入 2');
};
index.js
const btn = document.querySelector('.btn');
btn.onclick = import('./print.js').then((module) => {
const print = module.default;
print();});
13.3 Vue 按需加载
返回目录
Vue 的特点就是 SPA – Single Page Application(单页应用程序)。
只有第一次加载页面,当前的每次页面切换,只须要进行组件替换。
它缩小了申请次数,放慢页面响应速度,升高对服务器压力等等。
然而,因为 Vue 是 SPA,所以首页第一次加载时会把所有组件以及组件相干资源全副加载,从而导致网站首页关上速度变慢,升高用户体验。
Vue 我的项目中,能够联合 Webpack,在 vue-router
通过 import
进行动静加载:
const routes = [{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue')
}];
十四 常识补充:热更新
返回目录
刷新咱们个别分为两种:
- 一种是页面刷新,不保留页面状态,就是简略粗犷,间接
window.location.reload()
。 - 另一种是基于
WDS
(Webpack-dev-server
)的模块热替换,只须要部分刷新页面上发生变化的模块,同时能够保留以后的页面状态,比方复选框的选中状态、输入框的输出等。
Webpack
的热更新又称热替换(Hot Module Replacement
),缩写为 HMR
。
这个机制能够做到不必刷新浏览器而将新变更的模块替换掉旧的模块。
14.1 开启热更新
返回目录
在 Webpack 的 webpack.config.js
中:
- 配置
devServer
的hot
为true
- 在
plugins
中减少new webpack.HotModuleReplacementPlugin()
// webpack.config.js
const webpack = require('webpack');
module.exports = {
//....
devServer: {hot: true},
plugins: [new webpack.HotModuleReplacementPlugin() // 热更新插件
]
}
并且在入口文件配置:
if(module && module.hot) {module.hot.accept()
}
此时批改代码的时候,只有对应局部的内容才会相应更新。
14.2 热更新原理
返回目录
HMR
的外围就是客户端从服务端拉去更新后的文件,精确的说是 chunk diff
(chunk
须要更新的局部)。
实际上 webpack-dev-server
(WDS
)与浏览器之间保护了一个 Websocket
,当本地资源发生变化时,WDS
会向浏览器推送更新,并带上构建时的 hash
,让客户端与上一次资源进行比照。
客户端比照出差别后会向 WDS
发动 Ajax
申请来获取更改内容(文件列表、hash
),这样客户端就能够再借助这些信息持续向 WDS
发动 jsonp
申请获取该 chunk
的增量更新。
后续的局部(拿到增量更新之后如何解决?哪些状态该保留?哪些又须要更新?)由 HotModulePlugin
来实现,提供了相干 API
以供开发者针对本身场景进行解决,像 react-hot-loader
和 vue-loader
都是借助这些 API
实现 HMR
。
十五 常识补充:3 种 hash
返回目录
文件指纹是打包后输入的文件名的后缀,对应着 3 种 hash
。
hash
是跟整个我的项目的构建相干,只有我的项目里有文件更改,整个我的项目构建的hash
值都会更改,并且全副文件都共用雷同的hash
值。(粒度整个我的项目)chunkhash
是依据不同的入口进行依赖文件解析,构建对应的chunk
(模块),生成对应的hash
值。只有被批改的chunk
(模块)在从新构建之后才会生成新的hash
值,不会影响其它的chunk
。(粒度entry
的每个入口文件)contenthash
是跟每个生成的文件无关,每个文件都有一个惟一的hash
值。当要构建的文件内容产生扭转时,就会生成新的hash
值,且该文件的扭转并不会影响和它同一个模块下的其它文件。(粒度每个文件的内容)
十六 常识补充:source map
返回目录
source map
是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就须要 soucre map
。
map
文件只有不关上开发者工具,浏览器是不会加载的。
线上环境个别有三种解决计划:
hidden-source-map
:借助第三方谬误监控平台Sentry
应用nosources-source-map
:只会显示具体行数以及查看源代码的谬误栈。安全性比source map
高source map
:通过nginx
设置将.map
文件只对白名单凋谢(公司内网)
留神:防止在生产中应用 inline-
和 eval-
,因为它们会减少 bundle
体积大小,并升高整体性能。
十七 常识补充:Webpack 打包原理
返回目录
- Webpack 简略实现
在 Webpack 简略实现中,简略的做了下如何将一份代码进行打包:
- 利用
babel
实现代码转换,并生成单个文件的依赖 - 生成依赖图谱
- 生成最初打包代码
十八 参考文献
返回目录
本系列参考文献有 51 篇文章。
18.1 Webpack 系列文章
返回目录
其余 :
- [x] Webpack 中文文档【浏览倡议:无】
- [x] Webpack 小书【浏览倡议:无】
2020 年文章 :
- [x]「吐血整顿」再来一打 Webpack 面试题【浏览倡议:1h】
- [x] 带你深度解锁 Webpack 系列 (根底篇)【浏览倡议:1h】
- [x] 带你深度解锁 Webpack 系列 (进阶篇)【浏览倡议:30min】
- [x] 带你深度解锁 Webpack 系列 (优化篇)【浏览倡议:20min】
- [x] webpack loader 从上手到了解系列:vue-loader【浏览倡议:20min】
- [x] webpack loader 从上手到了解系列:style-loader【浏览倡议:20min】
- [x] 霖呆呆的 webpack 之路 -loader 篇【浏览倡议:20min】
- [x] 揭秘 webpack plugin【浏览倡议:30min】
2019 年文章 :
- [x] 对于 webpack4 的 14 个知识点, 童叟无欺【浏览倡议:30min】
- [x] 实现一个简略的 webpack【浏览倡议:1h】
- [x] 一文把握 Webpack 编译流程【浏览倡议:1h】
- [x] 前端工程师都得把握的 webpack Loader【浏览倡议:30min】
- [x] 轻松了解 webpack 热更新原理【浏览倡议:1h】
- [x] webpack 中那些最易混同的 5 个知识点【浏览倡议:30min】
2018 年文章 :
- [x] 手把手教你撸一个 Webpack Loader【浏览倡议:1h】
- [x] 手把手教你撸一个繁难的 webpack【浏览倡议:30min】
- [x] Webpack 揭秘——走向高阶前端的必经之路【浏览倡议:30min】
- [x] webpack 详解【浏览倡议:1h】
- [x] webpack4- 用之初体验,一起敲它十一遍【浏览倡议:30min】
- [x] 带你走进 webpack 世界,成为 webpack 头等玩家。【浏览倡议:20min】
- [x]【webpack 进阶】你真的把握了 loader 么?- loader 十问【浏览倡议:20min】
- [x] webpack 打包之后的文件过大的解决办法【浏览倡议:10min】
- [x] 基于 Webpack 搭建 React 开发环境【浏览倡议:10min】
2017 文章 :
- [x] Webpack 源码(一)—— Tapable 和 事件流【浏览倡议:10min】
18.2 Webpack 性能优化
返回目录
2019 年文章 :
- [x] Webpack 优化——将你的构建效率提速翻倍【浏览倡议:10min】
- [x] 性能优化篇 —Webpack 构建速度优化【浏览倡议:10min】
- [x] 应用 webpack4 晋升 180% 编译速度【浏览倡议:10min】
- [x] 多过程并行压缩代码【浏览倡议:5min】
- [x] webpack 4: Code Splitting 和 chunks 切分优化【浏览倡议:5min】
2018 年文章 :
- [x] Tree-Shaking 性能优化实际 – 原理篇【浏览倡议:10min】
- [x] 体积缩小 80%!开释 webpack tree-shaking 的真正后劲【浏览倡议:10min】
- [x] 你的 Tree-Shaking 并没什么卵用【浏览倡议:5min】
- [x] webpack 如何通过作用域剖析打消无用代码【浏览倡议:5min】
- [x] 让你的 Webpack 腾飞—考拉会员后盾 Webpack 优化实战【浏览倡议:5min】
- [x] webpack dllPlugin 打包体积和速度优化【浏览倡议:5min】
- [x] webpack 优化之 code splitting【浏览倡议:5min】
2017 年文章 :
- [x] Webpack 打包优化之速度篇【浏览倡议:5min】
- [x] 减速 Webpack- 放大文件搜寻范畴【浏览倡议:5min】
- [x] Webpack 大法之 Code Splitting【浏览倡议:5min】
18.3 Scope Hoisting
返回目录
- [x] webpack 的 scope hoisting 是什么?【浏览倡议:5min】
- [x] 通过 Scope Hoisting 优化 Webpack 输入【浏览倡议:5min】
- [x]【Webpack】654- 了不起的 Webpack Scope Hoisting 学习指南【浏览倡议:5min】
18.4 Tree Shaking
返回目录
- [x] Tree Shaking – Webpack 5.0.0-rc.0【浏览倡议:仅供参考】
- [x] Webpack 4 Tree Shaking 终极优化指南【浏览倡议:30min】
- [x] Tree-Shaking 性能优化实际 – 原理篇 – 2018【浏览倡议:仅供参考】
- [x] Webpack4: Tree-shaking 深度解析 – 2019【浏览倡议:仅供参考】
18.5 懒加载
返回目录
- [x] Vue Webpack 打包优化——路由懒加载(按需加载)原理解说及应用办法阐明【浏览倡议:20min】
- [x] 懒加载 – Webpack v5.0.0-rc.0【浏览倡议:5min】
- [x] webpack 的代码宰割(路由懒加载同理)【浏览倡议:10min】
jsliang 的文档库由 梁峻荣 采纳 常识共享 署名 - 非商业性应用 - 雷同形式共享 4.0 国内 许可协定 进行许可。<br/> 基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/> 本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。