├── .babelrc ├── .dockerignore ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── Dockerfile ├── README.md ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── actions.js ├── assets │ └── logo.png ├── components │ └── Loader.vue ├── main.js └── store.js ├── vue.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }] 9 | ], 10 | "plugins": ["@babel/transform-runtime"] 11 | } 12 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 13 | extends: ['plugin:vue/essential'], 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'vue' 17 | ], 18 | // check if imports actually resolve 19 | settings: { 20 | 'import/resolver': { 21 | webpack: { 22 | config: 'build/webpack.base.conf.js' 23 | } 24 | } 25 | }, 26 | // add your custom rules here 27 | rules: { 28 | // allow debugger during development 29 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | /test/unit/coverage/ 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.sln 16 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12-alpine 2 | 3 | RUN npm install -g http-server 4 | 5 | COPY package*.json ./ 6 | 7 | RUN yarn 8 | 9 | COPY . . 10 | 11 | RUN yarn build 12 | 13 | EXPOSE 8080 14 | CMD [ "http-server", "dist" ] 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # test-project 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | 20 | # run unit tests 21 | npm run unit 22 | 23 | # run all tests 24 | npm test 25 | ``` 26 | 27 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-off-main-thread-architecture", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@vue/cli-plugin-babel": "4.1.1", 12 | "@vue/cli-plugin-eslint": "4.1.1", 13 | "@vue/cli-service": "4.1.1", 14 | "vue": "^2.6.11", 15 | "vuex": "3.1.2", 16 | "worker-plugin": "3.2.0" 17 | }, 18 | "devDependencies": { 19 | "babel-eslint": "^10.0.3", 20 | "eslint": "^6.7.2", 21 | "eslint-plugin-vue": "^6.0.1", 22 | "vue-template-compiler": "^2.6.11" 23 | }, 24 | "eslintConfig": { 25 | "root": true, 26 | "env": { 27 | "node": true 28 | }, 29 | "extends": ["plugin:vue/essential", "eslint:recommended"], 30 | "rules": {}, 31 | "parserOptions": { 32 | "parser": "babel-eslint" 33 | } 34 | }, 35 | "postcss": { 36 | "plugins": { 37 | "autoprefixer": {} 38 | } 39 | }, 40 | "browserslist": ["> 1%", "last 2 versions", "not ie <= 8"], 41 | "keywords": [], 42 | "description": "Workers magic" 43 | } 44 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logaretm/vuex-off-main-thread/2df2194730a483cd46e9194e54bed48b89b040ad/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | codesandbox 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 26 | 27 | 61 | -------------------------------------------------------------------------------- /src/actions.js: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Tools/Performance/Scenarios/Intensive_JavaScript 2 | function calculatePrimes(iterations, multiplier) { 3 | var primes = []; 4 | const now = Date.now(); 5 | 6 | // Casual UI-Locking code for 2 seconds! 7 | while (now + 2000 >= Date.now()); 8 | 9 | // Heavy computation! 10 | for (var i = 0; i < iterations; i++) { 11 | var candidate = i * (multiplier * Math.random()); 12 | var isPrime = true; 13 | for (var c = 2; c <= Math.sqrt(candidate); ++c) { 14 | if (candidate % c === 0) { 15 | // not prime 16 | isPrime = false; 17 | break; 18 | } 19 | } 20 | if (isPrime) { 21 | primes.push(candidate); 22 | } 23 | } 24 | return primes; 25 | } 26 | 27 | onmessage = e => { 28 | if (e.data === "generateItems") { 29 | // Perform the calculation 30 | self.postMessage({ type: "SET_WORKING", payload: true }); 31 | const primes = calculatePrimes(400, 1000000000); 32 | self.postMessage({ type: "SET_ITEMS", payload: primes }); 33 | self.postMessage({ type: "SET_WORKING", payload: false }); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logaretm/vuex-off-main-thread/2df2194730a483cd46e9194e54bed48b89b040ad/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Loader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 18 | 19 | 20 | 107 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import store from "./store"; 4 | 5 | Vue.config.productionTip = false; 6 | 7 | new Vue({ 8 | store, 9 | render: h => h(App) 10 | }).$mount("#app"); 11 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vuex from "vuex"; 2 | import Vue from "vue"; 3 | 4 | const actions = new Worker("./actions.js", { type: 'module' }); 5 | 6 | Vue.use(Vuex); 7 | 8 | const store = new Vuex.Store({ 9 | state: { 10 | items: [], 11 | isWorking: false 12 | }, 13 | mutations: { 14 | SET_ITEMS(state, items) { 15 | state.items = items; 16 | }, 17 | SET_WORKING(state, value) { 18 | state.isWorking = value; 19 | } 20 | }, 21 | actions: { 22 | generateItems() { 23 | actions.postMessage("generateItems"); 24 | } 25 | } 26 | }); 27 | 28 | actions.onmessage = e => { 29 | store.commit(e.data.type, e.data.payload); 30 | }; 31 | 32 | export default store; 33 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const WorkerPlugin = require("worker-plugin"); 3 | 4 | module.exports = { 5 | chainWebpack: config => { 6 | config.plugin("worker").use(WorkerPlugin); 7 | } 8 | }; 9 | --------------------------------------------------------------------------------