├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── ModelView_WallpaperEngine_template.html ├── ProcessControlPlugin.js ├── README.md ├── dist └── .gitkeep ├── example └── image_2020-06-22_21-38-48.png ├── imgs └── show.png ├── index.html ├── index.js ├── lib └── marmoset.js ├── model ├── scene.mview └── test.mview ├── music └── LaSoLa.mp3 ├── outputDir └── all.bundle.js ├── package-lock.json ├── package.json ├── wallper.config.js └── webpack.config.js /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v2 12 | with: 13 | persist-credentials: false 14 | 15 | - name: Install and Build 🔧 16 | run: | 17 | npm install 18 | 19 | npm run-script build 20 | 21 | - name: Deploy to GitHub Pages 22 | uses: JamesIves/github-pages-deploy-action@3.5.5 23 | with: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | BRANCH: gh-pages 26 | FOLDER: dist 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | node_modules 4 | dist/index.html 5 | outputDir/index.html 6 | model -------------------------------------------------------------------------------- /ModelView_WallpaperEngine_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 13 | 14 | 17 | 18 | 19 | 20 | 23 | 66 | 67 | 68 | 69 |
70 | 73 | 74 | 77 | 78 | -------------------------------------------------------------------------------- /ProcessControlPlugin.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | let CustomPlugin = function(options) { 5 | options = options || {}; 6 | this.options = options; 7 | }; 8 | 9 | CustomPlugin.prototype.apply = function(compiler) { 10 | // 如果希望在生成的资源输出到output指定目录之前执行某个功能 11 | compiler.hooks.emit.tap("ProcessControl", () => {}); 12 | 13 | // 编译完成之后 14 | compiler.hooks.done.tap("ProcessControl", () => { 15 | // 执行一次图片封装解析 16 | var sourceFile = path.join(__dirname, "outputDir/index.html"); 17 | var destPath = path.join(__dirname, "dist", "index.html"); 18 | var readStream = fs.createReadStream(sourceFile); 19 | var writeStream = fs.createWriteStream(destPath); 20 | readStream.pipe(writeStream); 21 | console.log("move done"); 22 | try { 23 | fs.unlinkSync("outputDir/index.html"); 24 | //file removed 25 | } catch (err) { 26 | console.error(err); 27 | } 28 | }); 29 | }; 30 | 31 | module.exports = CustomPlugin; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # what's this 2 | 3 | it's teamplate export a single html with webpack,nodejs, make images to base64 to show, 4 | and with .mview model. 5 | 6 | 可以将图片和模型导出为完整html,配合wallperEngine 可做壁纸,使用ModelView_WallpaperEngine_templatee.html模版导出 7 | 8 | ## [model demo](https://github.com/ChenYCL/single-html/tree/wallpaper) 9 | 10 | # rules 11 | 12 | - imgs 13 | dir collect image 14 | 15 | 放置图片的文件夹,将会自动打包 16 | 17 | - model 18 | dir collect .mview etc 19 | 20 | 放置模型的文件夹,将会自动打包 21 | 22 | # use 23 | 24 | ```$javascript 25 | npm install 26 | npm run fix-memory-limit 27 | npm run build // normal 28 | npm run wallper // for wallper engine 29 | 30 | // export dist/index.html 31 | // 导出位置 dist/index.htl 32 | 33 | 34 | ``` 35 | 36 | global variable on window 37 | 38 | [filename]\_model - model object,if imgs dir have scene.mview 39 | 40 | 模型变量 文件名_model 41 | 42 | eg. scene_model 43 | 44 | [filename]\_img - image object,if imgs dir have show.png 45 | 46 | 图片变量 文件名_img 47 | 48 | eg. show_img 49 | 50 | # Preview 51 | 52 | ![image.png](https://i.loli.net/2020/06/20/u8rftObwxcnqMg3.png) 53 | 54 | ## wallpaper_engine 55 | 56 | ![image.png](https://github.com/ChenYCL/single-html/blob/master/example/image_2020-06-22_21-38-48.png) 57 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file !.gitkeep -------------------------------------------------------------------------------- /example/image_2020-06-22_21-38-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/example/image_2020-06-22_21-38-48.png -------------------------------------------------------------------------------- /imgs/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/imgs/show.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 13 | 14 | 17 | 20 | 23 | 70 | 71 | 72 | 73 |
74 | 75 | 76 |

desc here...

77 |

first pic

78 | 79 | 82 |

second pic

83 | 84 | 85 | 96 | 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var marmoset = require("./lib/marmoset"); -------------------------------------------------------------------------------- /model/scene.mview: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/model/scene.mview -------------------------------------------------------------------------------- /model/test.mview: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/model/test.mview -------------------------------------------------------------------------------- /music/LaSoLa.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/music/LaSoLa.mp3 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-base64", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --config webpack.config.js", 8 | "wallper": "webpack --config wallper.config.js", 9 | "fix-memory-limit": "cross-env LIMIT=8096 increase-memory-limit" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "copy-webpack-plugin": "^6.0.2", 15 | "fs-extra": "^9.0.1", 16 | "webpack-parallel-uglify-plugin": "^1.1.2" 17 | }, 18 | "devDependencies": { 19 | "clean-webpack-plugin": "^3.0.0", 20 | "cross-env": "^7.0.2", 21 | "css-loader": "^3.6.0", 22 | "extract-loader": "^5.1.0", 23 | "file-loader": "^6.0.0", 24 | "html-loader": "^1.1.0", 25 | "html-webpack-plugin": "^4.3.0", 26 | "increase-memory-limit": "^1.0.7", 27 | "raw-loader": "^4.0.1", 28 | "style-loader": "^1.2.1", 29 | "url-loader": "^4.1.0", 30 | "webpack": "^4.43.0", 31 | "webpack-cli": "^3.3.12" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /wallper.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); // installed via npm 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 5 | const ProcessControlPlugin = require('./ProcessControlPlugin'); 6 | const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); 7 | const CopyPlugin = require('copy-webpack-plugin'); 8 | 9 | console.log('Build process is starting'); 10 | // try { 11 | // fs.unlinkSync('outputDir/index.html') 12 | // //file removed 13 | // } catch(err) { 14 | // console.error(err) 15 | // } 16 | 17 | let modelOBJ = {}; 18 | let modelArr = fs.readdirSync('./model'); 19 | modelArr.map((filename, idx) => { 20 | // 模型转 base64 21 | if(filename === 'test'){return false}; 22 | var buff = fs.readFileSync(`./model/${filename}`); 23 | var base64data = buff.toString('base64'); 24 | modelOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 25 | //console.log(base64data); 26 | }); 27 | console.log('\n模型转换完毕...\n'); 28 | 29 | 30 | let mp3OBJ = {}; 31 | let mp3Arr = fs.readdirSync('./music'); 32 | mp3Arr.map((filename, idx) => { 33 | // 模型转 base64 34 | var buff = fs.readFileSync(`./music/${filename}`); 35 | var base64data = buff.toString('base64'); 36 | mp3OBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 37 | // console.log(base64data); 38 | }); 39 | console.log('\n音频转换完毕...\n'); 40 | 41 | // image -> base64 42 | let imgOBJ = {}; 43 | let imgArr = fs.readdirSync('./imgs'); 44 | imgArr.map((filename, idx) => { 45 | // 模型转 base64 46 | var buff = fs.readFileSync(`./imgs/${filename}`); 47 | var base64data = Buffer.from(buff, 'binary').toString('base64'); 48 | imgOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 49 | //console.log(base64data); 50 | }); 51 | console.log('\n图片转换完毕...开始打包\n'); 52 | 53 | module.exports = { 54 | entry: './index.js', 55 | output: { 56 | path: path.resolve(__dirname, 'outputDir'), 57 | filename: 'all.bundle.js', 58 | }, 59 | mode: 'production', 60 | module: { 61 | rules: [ 62 | { 63 | test: /\.(png|jpg|gif|jpeg|svg)$/i, 64 | use: [ 65 | { 66 | loader: 'url-loader', 67 | options: { 68 | limit: 99999999999999999, 69 | name: 'images/[name]-[hash:8].[ext]', 70 | }, 71 | }, 72 | ], 73 | }, 74 | // { 75 | // test: /\.js$/i, 76 | // loader: "file-loader", 77 | // }, 78 | { test: /\.txt$/, use: 'raw-loader' }, 79 | { test: /\.css$/, use: 'css-loader', exclude: /node_modules/ }, 80 | { test: /\.css$/, use: 'style-loader', exclude: /node_modules/ }, 81 | ], 82 | }, 83 | plugins: [ 84 | new ProcessControlPlugin(), 85 | // new ParallelUglifyPlugin({ 86 | // cacheDir: "./node_modules/cache/", 87 | // uglifyJS: { 88 | // output: { 89 | // comments: false, 90 | // }, 91 | // warnings: false, 92 | // }, 93 | // }), 94 | 95 | new HtmlWebpackPlugin({ 96 | template: './ModelView_WallpaperEngine_template.html', 97 | filename: 'index.html', 98 | title: "it's a template1", 99 | inject: false, 100 | templateParameters: { 101 | model_base64_data: (() => { 102 | let script = ''; 103 | for (key in modelOBJ) { 104 | script += `var ${key}_model = "${modelOBJ[key]}";\n`; 105 | } 106 | return script; 107 | })(), 108 | images_base64_data: (() => { 109 | let script = ''; 110 | for (key in imgOBJ) { 111 | script += `var ${key}_img = "${imgOBJ[key]}";\n`; 112 | } 113 | return script; 114 | })(), 115 | mp3_base64_data: (() => { 116 | let script = ''; 117 | for (key in mp3OBJ) { 118 | script += `var ${key}_mp3 = "${mp3OBJ[key]}";\n`; 119 | } 120 | return script; 121 | })(), 122 | myscript: (() => { 123 | const d = fs.readFileSync( 124 | 'outputDir/all.bundle.js', 125 | async (err, data) => { 126 | return data; 127 | } 128 | ); 129 | return d; 130 | })(), 131 | }, 132 | // minify: { 133 | // //删除html空格 134 | // collapseWhitespace: true, 135 | // //尽可能使用直接Unicode字符 136 | // decodeEntities: true, 137 | // //指定最大行长度。压缩输出将在有效的HTML分割点按换行符分割 138 | // // maxLineLength:30, 139 | // //在样式元素和样式属性中缩小CSS(使用clean-css) 140 | // minifyCSS: true, 141 | // //缩小脚本元素和事件属性中的JavaScript(使用UglifyJS) 142 | // minifyJS: true, 143 | // //尽可能删除属性周围的引号 144 | // removeAttributeQuotes: true, 145 | // //删除内容为空的属性 146 | // removeEmptyAttributes: true, 147 | // }, 148 | }), 149 | 150 | // new CopyPlugin({ 151 | // patterns: [ 152 | // {from: './outputDir/index.html', to: './dist/'} 153 | // ] 154 | // }), 155 | ], 156 | }; 157 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); // installed via npm 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 5 | const ProcessControlPlugin = require('./ProcessControlPlugin'); 6 | const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); 7 | const CopyPlugin = require('copy-webpack-plugin'); 8 | 9 | console.log('Build process is starting'); 10 | // try { 11 | // fs.unlinkSync('outputDir/index.html') 12 | // //file removed 13 | // } catch(err) { 14 | // console.error(err) 15 | // } 16 | 17 | let modelOBJ = {}; 18 | let modelArr = fs.readdirSync('./model'); 19 | modelArr.map((filename, idx) => { 20 | // 模型转 base64 21 | var buff = fs.readFileSync(`./model/${filename}`); 22 | var base64data = buff.toString('base64'); 23 | modelOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 24 | //console.log(base64data); 25 | }); 26 | console.log('\n模型转换完毕...\n'); 27 | 28 | 29 | let mp3OBJ = {}; 30 | let mp3Arr = fs.readdirSync('./music'); 31 | mp3Arr.map((filename, idx) => { 32 | // 模型转 base64 33 | var buff = fs.readFileSync(`./music/${filename}`); 34 | var base64data = buff.toString('base64'); 35 | mp3OBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 36 | // console.log(base64data); 37 | }); 38 | console.log('\n音频转换完毕...\n'); 39 | 40 | // image -> base64 41 | let imgOBJ = {}; 42 | let imgArr = fs.readdirSync('./imgs'); 43 | imgArr.map((filename, idx) => { 44 | // 模型转 base64 45 | var buff = fs.readFileSync(`./imgs/${filename}`); 46 | var base64data = Buffer.from(buff, 'binary').toString('base64'); 47 | imgOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data; 48 | //console.log(base64data); 49 | }); 50 | console.log('\n图片转换完毕...开始打包\n'); 51 | 52 | module.exports = { 53 | entry: './index.js', 54 | output: { 55 | path: path.resolve(__dirname, 'outputDir'), 56 | filename: 'all.bundle.js', 57 | }, 58 | mode: 'production', 59 | module: { 60 | rules: [ 61 | { 62 | test: /\.(png|jpg|gif|jpeg|svg)$/i, 63 | use: [ 64 | { 65 | loader: 'url-loader', 66 | options: { 67 | limit: 99999999999999999, 68 | name: 'images/[name]-[hash:8].[ext]', 69 | }, 70 | }, 71 | ], 72 | }, 73 | // { 74 | // test: /\.js$/i, 75 | // loader: "file-loader", 76 | // }, 77 | { test: /\.txt$/, use: 'raw-loader' }, 78 | { test: /\.css$/, use: 'css-loader', exclude: /node_modules/ }, 79 | { test: /\.css$/, use: 'style-loader', exclude: /node_modules/ }, 80 | ], 81 | }, 82 | plugins: [ 83 | new ProcessControlPlugin(), 84 | // new ParallelUglifyPlugin({ 85 | // cacheDir: "./node_modules/cache/", 86 | // uglifyJS: { 87 | // output: { 88 | // comments: false, 89 | // }, 90 | // warnings: false, 91 | // }, 92 | // }), 93 | 94 | new HtmlWebpackPlugin({ 95 | template: './index.html', 96 | filename: 'index.html', 97 | title: "it's a template1", 98 | inject: false, 99 | templateParameters: { 100 | // 模型注入 101 | model_base64_data: (() => { 102 | let script = ''; 103 | for (key in modelOBJ) { 104 | script += `var ${key}_model = "${modelOBJ[key]}";\n`; 105 | } 106 | return script; 107 | })(), 108 | // 图片注入 109 | images_base64_data: (() => { 110 | let script = ''; 111 | for (key in imgOBJ) { 112 | script += `var ${key}_img = "${imgOBJ[key]}";\n`; 113 | } 114 | return script; 115 | })(), 116 | // 音频注入 117 | mp3_base64_data: (() => { 118 | let script = ''; 119 | for (key in mp3OBJ) { 120 | script += `var ${key}_mp3 = "${mp3OBJ[key]}";\n`; 121 | } 122 | return script; 123 | })(), 124 | myscript: (() => { 125 | const d = fs.readFileSync( 126 | 'outputDir/all.bundle.js', 127 | async (err, data) => { 128 | return data; 129 | } 130 | ); 131 | return d; 132 | })(), 133 | }, 134 | // minify: { 135 | // //删除html空格 136 | // collapseWhitespace: true, 137 | // //尽可能使用直接Unicode字符 138 | // decodeEntities: true, 139 | // //指定最大行长度。压缩输出将在有效的HTML分割点按换行符分割 140 | // // maxLineLength:30, 141 | // //在样式元素和样式属性中缩小CSS(使用clean-css) 142 | // minifyCSS: true, 143 | // //缩小脚本元素和事件属性中的JavaScript(使用UglifyJS) 144 | // minifyJS: true, 145 | // //尽可能删除属性周围的引号 146 | // removeAttributeQuotes: true, 147 | // //删除内容为空的属性 148 | // removeEmptyAttributes: true, 149 | // }, 150 | }), 151 | 152 | // new CopyPlugin({ 153 | // patterns: [ 154 | // {from: './outputDir/index.html', to: './dist/'} 155 | // ] 156 | // }), 157 | ], 158 | }; 159 | --------------------------------------------------------------------------------