├── package.json ├── LICENSE ├── .gitignore ├── README.md └── index.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-aliyun-oss-plugin", 3 | "version": "2.1.0", 4 | "description": "上传webpack编译后的文件到阿里云OSS", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mfylee/webpack-aliyun-oss-plugin.git" 12 | }, 13 | "keywords": [ 14 | "webpack", 15 | "aliyun", 16 | "oss" 17 | ], 18 | "author": "mfylee@163.com", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/mfylee/webpack-aliyun-oss-plugin/issues" 22 | }, 23 | "homepage": "https://github.com/mfylee/webpack-aliyun-oss-plugin#readme", 24 | "dependencies": { 25 | "ali-oss": "^6.0.0", 26 | "async": "^2.5.0", 27 | "co": "^4.6.0", 28 | "config-file-loader": "^1.0.0", 29 | "underscore": "^1.8.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 mfylee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webpack-aliyun-oss-plugin 2 | >上传 webpack 编译后的文件到阿里云 OSS 3 | 4 | ## 使用说明 5 | - 第一步:安装依赖 6 | ``` 7 | npm install webpack-aliyun-oss-plugin --save-dev 8 | ``` 9 | - 第二步:配置 webpack.config.js 10 | ``` 11 | const WebpackAliyunOssPlugin = require('webpack-aliyun-oss-plugin'); 12 | 13 | module.exports = { 14 | output: { 15 | // 必须是标准的域名+路径,已`/`结尾 16 | publicPath: 'http://domain.com/path/to/deply/' 17 | }, 18 | plugins: [ 19 | // 建议只在生产环境配置代码上传 20 | new WebpackAliyunOssPlugin({ 21 | bucket: 'BucketName', 22 | account: 'account1', 23 | region: 'oss-cn-hangzhou', // bucket所在区域的接入点 24 | filter: function (asset) { 25 | return !/\.html$/.test(asset); 26 | } 27 | }) 28 | ] 29 | }; 30 | ``` 31 | 32 | ## 配置参数 33 | - ak(String) 34 | 阿里云授权 accessKeyId,必填项,可以由配置文件方式设置 35 | - sk(String) 36 | 阿里云授权 accessKeySecret,必填项,可以由配置文件方式设置 37 | - bucket(String) 38 | 需要上传到的 bucket 的名称 39 | - region(String) 40 | bucket 所在的区域,如果是在阿里云机器上,可以使用内部 region,节省流量 41 | - filter(Function(filepath)) 42 | 文件过滤器,通过该方法可自由决定哪些文件需要上传 43 | - account(String) 44 | 多账号支持,可以在 `.aliyun` 配置文件中配置多个子账号 45 | 46 | 47 | ## accessKeyId & accessKeySecret 保密 48 | 如果将 `accessKeyId` 和 `accessKeySecret` 直接写到代码中势必造成了安全隐患,为了安全起见,可以将敏感信息保存到编译机的配置文件中 49 | 50 | #### 配置方法 51 | 在编译机的 `$HOME`,也就是用户的根目录下创建 `.aliyun` 文件,并设置 `600` 权限 52 | ``` 53 | $ cd ~ 54 | $ echo "ak:xxxx\nsk:xxx" > .aliyun 55 | $ chmod 600 .aliyun 56 | ``` 57 | 其中 `ak` 为 accessKeyId,`sk` 为 accessKeySecret 58 | 59 | #### 多账号支持 60 | ``` 61 | $ cd ~ 62 | $ echo "account1:\nak:xxxx\nsk:xxx\naccount2:\nak:yyy\nsk:yyyy" > .aliyun 63 | $ chmod 600 .aliyun 64 | ``` 65 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * 上传webpack编译后的文件到阿里云OSS 3 | * 4 | * @author mfylee@163.com 5 | * @since 2017-08-23 6 | */ 7 | 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | var url = require('url'); 11 | 12 | var OSS = require('ali-oss').Wrapper; 13 | 14 | var u = require('underscore'); 15 | 16 | var ConfigFileLoader = require('config-file-loader'); 17 | /** 18 | * 读取全局配置 19 | * ~/.aliyun 20 | * @link https://github.com/reyesr/config-file-loader 21 | */ 22 | var aliyunConfig = new ConfigFileLoader.Loader().get('aliyun'); 23 | 24 | // 默认配置参数 25 | var DEFAULT_OPTIONS = { 26 | ak: '', 27 | sk: '', 28 | bucket: '', 29 | region: '', 30 | retry: 3, 31 | // 多账号支持 32 | account: null, 33 | filter: function (file) { 34 | return true; 35 | } 36 | }; 37 | /** 38 | * @constructor 39 | */ 40 | function WebpackAliyunOssPlugin(options) { 41 | this.options = u.extend({}, DEFAULT_OPTIONS, options); 42 | 43 | var conf = options.account ? aliyunConfig[options.account] : aliyunConfig; 44 | 45 | this.client = new OSS({ 46 | region: this.options.region || conf.region, 47 | accessKeyId: this.options.ak || conf.ak, 48 | accessKeySecret: this.options.sk || conf.sk 49 | }); 50 | 51 | this.client.useBucket(this.options.bucket); 52 | } 53 | 54 | WebpackAliyunOssPlugin.prototype.apply = function (compiler) { 55 | var me = this; 56 | compiler.hooks.emit.tapAsync('WebpackAliyunOssPlugin', function (compilation, callback) { 57 | var publicPath = url.parse(compiler.options.output.publicPath); 58 | if (!publicPath.protocol || !publicPath.hostname) { 59 | return callback(new Error('Webpack配置文件中: "output.publicPath"必须设置为域名,例如: https://domain.com/path/')); 60 | } 61 | 62 | var files = u.filter(u.keys(compilation.assets), me.options.filter); 63 | 64 | if (files.length === 0) { 65 | return callback(); 66 | } 67 | 68 | function upload(file, times) { 69 | var target = url.resolve(url.format(publicPath), file); 70 | var key = url.parse(target).pathname; 71 | var source = compilation.assets[file].source(); 72 | var body = Buffer.isBuffer(source) ? source : new Buffer(source, 'utf8'); 73 | return me.client.put(key, body, { 74 | timeout: 30 * 1000 75 | }).then(function () { 76 | console.log('[WebpackAliyunOssPlugin SUCCESS]:', key); 77 | var next = files.shift(); 78 | if (next) { 79 | return upload(next, me.options.retry); 80 | } 81 | }, function (e) { 82 | if (times === 0) { 83 | throw new Error('[WebpackAliyunOssPlugin ERROR]: ', e); 84 | } 85 | else { 86 | console.log('[WebpackAliyunOssPlugin retry]:', times, key); 87 | return upload(file, --times); 88 | } 89 | }); 90 | } 91 | upload(files.shift(), me.options.retry).then(function () { 92 | console.log('[WebpackAliyunOssPlugin FINISHED]', 'All Completed'); 93 | callback(); 94 | }).catch(function (e) { 95 | console.log('[WebpackAliyunOssPlugin FAILED]', e); 96 | return callback(e); 97 | }); 98 | }); 99 | }; 100 | 101 | module.exports = WebpackAliyunOssPlugin; 102 | 103 | --------------------------------------------------------------------------------