我正在尝试运行从ES6迁移到Typescript的Electon应用程序。通过我的配置,我可以成功构建dll和main,但是在尝试运行时出现错误(SyntaxError:意外令牌...)。 目前,项目文件是打字稿和javascript文件的组合。
我使用以下依赖项(其中主要是):
"@babel/core": "^7.2.2", "@babel/register": "^7.0.0" and others @babel.
"electron": "6.0.2"
"react": "^16.9.0",
"typescript": "^3.5.3",
"webpack": "^4.39.2"
"build": "concurrently \"npm run build-main\" \"npm run build-renderer\"",
"build-dll": "cross-env NODE_ENV=development node --trace-warnings -r @babel/register ./node_modules/webpack/bin/webpack --config webpack.config.renderer.dev.dll.js --colors",
"build-e2e": "cross-env E2E_BUILD=true npm run build",
"build-main": "cross-env NODE_ENV=production node --trace-warnings -r @babel/register ./node_modules/webpack/bin/webpack --config webpack.config.main.prod.js --colors",
"build-renderer": "cross-env NODE_ENV=production node --trace-warnings -r @babel/register ./node_modules/webpack/bin/webpack --config webpack.config.renderer.prod.js --colors",
"electron-rebuild": "electron-rebuild --parallel --force --types prod,dev,optional --module-dir app",
"dev": "cross-env START_HOT=1 node -r @babel/register ./scripts/CheckPortInUse.js && cross-env START_HOT=1 npm run start-renderer-dev",
"start-main-dev": "cross-env HOT=1 NODE_ENV=development electron -r @babel/register ./app/main.dev.js",
"start-renderer-dev": "cross-env NODE_ENV=development node --trace-warnings -r @babel/register ./node_modules/webpack-dev-server/bin/webpack-dev-server --config webpack.config.renderer.dev.js",
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"outDir": "./dist",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"strictNullChecks": false,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"sourceMap": true,
"noImplicitAny": false,
"jsx": "react",
},
"include": [
"./app"
],
"exclude": [
"node_modules",
"**/node_modules/*",
"dist"
]
}
{
"presets": [
["@babel/preset-env", {
"targets": { "electron": "6.0.2" },
"corejs": "2",
"useBuiltIns": "usage"
}],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": [
// Stage 0
"@babel/plugin-proposal-function-bind",
// Stage 1
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-logical-assignment-operators",
["@babel/plugin-proposal-optional-chaining", {
"loose": false
}],
["@babel/plugin-proposal-pipeline-operator", {
"proposal": "minimal"
}],
["@babel/plugin-proposal-nullish-coalescing-operator", {
"loose": false
}],
"@babel/plugin-proposal-do-expressions",
// Stage 2
["@babel/plugin-proposal-decorators", {
"legacy": true
}],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions",
// Stage 3
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
"@babel/plugin-proposal-json-strings",
"@babel/plugin-proposal-object-rest-spread"
],
"env": {
"production": {
"plugins": [
"babel-plugin-dev-expression",
"@babel/plugin-transform-react-constant-elements",
"@babel/plugin-transform-react-inline-elements",
"babel-plugin-transform-react-remove-prop-types"
]
},
"development": {
"plugins": [
"@babel/plugin-syntax-typescript",
"react-hot-loader/babel"
]
}
}
}
import path from 'path';
import webpack from 'webpack';
import fs from 'fs';
import { dependencies as externals } from './app/package.json';
import { dependencies as possibleExternals } from './package.json';
export default {
externals: [
...Object.keys(externals || {}),
...Object.keys(possibleExternals ||{})
],
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
},
'ts-loader'
]
}
]
},
output: {
path: path.join(__dirname, 'app'),
// https://github.com/webpack/webpack/issues/1114
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
modules: [path.join(__dirname, 'app'), 'node_modules']
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'production'
}),
new webpack.NamedModulesPlugin()
]
};
/**
* Builds the DLL for development electron renderer process
*/
import webpack from 'webpack';
import path from 'path';
import merge from 'webpack-merge';
import baseConfig from './webpack.config.base';
import { dependencies } from './package.json';
import CheckNodeEnv from './scripts/CheckNodeEnv';
CheckNodeEnv('development');
const dist = path.resolve(process.cwd(), 'dll');
export default merge.smart(baseConfig, {
devtool: 'eval',
mode: 'development',
target: 'electron-renderer',
externals: ['fsevents', 'crypto-browserify'],
module: require('./webpack.config.renderer.dev').default.module,
entry: {
renderer: Object.keys(dependencies || {}).filter(
dependency => dependency !== 'font-awesome'
)
},
output: {
library: 'renderer',
path: dist,
filename: '[name].dev.dll.js',
libraryTarget: 'var'
},
plugins: [
new webpack.DllPlugin({
path: path.join(dist, '[name].json'),
name: '[name]'
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'development'
}),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: path.resolve(process.cwd(), 'app'),
output: {
path: path.resolve(process.cwd(), 'dll')
}
}
})
]
});
import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import chalk from 'chalk';
import merge from 'webpack-merge';
import { spawn, execSync } from 'child_process';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from './scripts/CheckNodeEnv';
CheckNodeEnv('development');
const port = process.env.PORT || 1212;
const publicPath = `http://localhost:${port}/dist`;
const dll = path.resolve(process.cwd(), 'dll');
const manifest = path.resolve(dll, 'renderer.json');
const requiredByDLLConfig = module.parent.filename.includes(
'webpack.config.renderer.dev.dll'
);
if (!requiredByDLLConfig && !(fs.existsSync(dll) && fs.existsSync(manifest))) {
execSync('npm run build-dll');
}
export default merge.smart(baseConfig, {
devtool: 'inline-source-map',
mode: 'development',
target: 'electron-renderer',
entry: [
'react-hot-loader/patch',
`webpack-dev-server/client?http://localhost:${port}/`,
'webpack/hot/only-dev-server',
path.join(__dirname, 'app/index.js')
],
output: {
publicPath: `http://localhost:${port}/dist/`,
filename: 'renderer.dev.js'
},
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
'@babel/preset-react'
],
plugins: [
'@babel/plugin-transform-runtime',
["@babel/plugin-proposal-class-properties", { "loose": true }],
'react-hot-loader/babel'
]
}
}
},
{
test: /\.global\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /^((?!\.global).)*\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
}
]
},
// SASS support - compile all .global.scss files and pipe it to style.css
{
test: /\.global\.(scss|sass)$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'sass-loader'
}
]
},
// SASS support - compile all other .scss files and pipe it to style.css
{
test: /^((?!\.global).)*\.(scss|sass)$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
{
loader: 'sass-loader'
}
]
},
// WOFF Font
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff'
}
}
},
// WOFF2 Font
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff'
}
}
},
// TTF Font
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream'
}
}
},
// EOT Font
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader'
},
// SVG Font
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml'
}
}
},
// Common Image Formats
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
use: 'url-loader'
},
// All files with a ".ts" or ".tsx" extension will be handled by "awesome-typescript-loader".
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
},
// All output ".js" files will have any sourcemaps re-processed by "source-map-loader".
{
test: /\.js$/,
enforce: "pre",
loader: "source-map-loader" }
]
},
plugins: [
requiredByDLLConfig
? null
: new webpack.DllReferencePlugin({
context: process.cwd(),
// eslint-disable-next-line global-require
manifest: require(manifest),
sourceType: 'var'
}),
new webpack.HotModuleReplacementPlugin({
multiStep: true
}),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.EnvironmentPlugin({
NODE_ENV: 'development'
}),
new webpack.LoaderOptionsPlugin({
debug: true
}),
new ExtractTextPlugin({
filename: '[name].css'
})
],
node: {
__dirname: false,
__filename: false
},
devServer: {
port,
publicPath,
compress: true,
noInfo: true,
stats: 'errors-only',
inline: true,
lazy: false,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
contentBase: path.join(__dirname, 'dist'),
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/,
poll: 100
},
historyApiFallback: {
verbose: true,
disableDotRule: false
},
before() {
if (process.env.START_HOT) {
console.log('Starting Main Process...');
spawn('npm', ['run', 'start-main-dev'], {
shell: true,
env: process.env,
stdio: 'inherit'
})
.on('close', code => process.exit(code))
.on('error', spawnError => console.error(spawnError));
}
}
}
});
错误消息:
SyntaxError: Unexpected token {
import { app, BrowserWindow } from 'electron';
^
at Module._compile (internal/modules/cjs/loader.js:722:23)
at Module._compile (C:\tool\node_modules\pirates\lib\index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:798:10)
at Object.newLoader [as .js] (C:\tool\node_modules\pirates\lib\index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:645:32)
at Function.Module._load (internal/modules/cjs/loader.js:560:12)
at loadApplicationPackage (C:\tool\node_modules\electron\dist\resources\default_app.asar\main.js:109:16)
at Object.<anonymous> (C:\tool\node_modules\electron\dist\resources\default_app.asar\main.js:155:9)
at Module._compile (internal/modules/cjs/loader.js:786:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:798:10)
更新:
正如 ford04 所说,需要使用commonjs或es2015,因为电子仅适用于es2015标准。还需要在.babelrc文件或webpack配置中设置babel预设/插件。
tsconfig.js
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"es2015",
"es6",
],
"outDir": "./dist",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"strictNullChecks": false,
"forceConsistentCasingInFileNames": true,
"module": "es2015",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"sourceMap": true,
"noImplicitAny": false,
"jsx": "react"
},
"include": [
"./app"
],
"exclude": [
"node_modules",
"**/node_modules/*",
"dist"
]
}
.babelrc我已根据electron-typescript替换为babel.config.js
const developmentEnvironments = ['development', 'test'];
const developmentPlugins = [
require('react-hot-loader/babel'),
require('@babel/plugin-syntax-typescript')
];
const productionPlugins = [
require('babel-plugin-dev-expression'),
// babel-preset-react-optimize
require('@babel/plugin-transform-react-constant-elements'),
require('@babel/plugin-transform-react-inline-elements'),
require('babel-plugin-transform-react-remove-prop-types')
];
module.exports = api => {
const development = api.env(developmentEnvironments);
return {
presets: [
[
require('@babel/preset-env'),
{
targets: { electron: require('electron/package.json').version },
useBuiltIns: 'usage',
corejs: 2
}
],
require('@babel/preset-typescript'),
[require('@babel/preset-react'), { development }]
],
plugins: [
// Stage 0
require('@babel/plugin-proposal-function-bind'),
// Stage 1
require('@babel/plugin-proposal-export-default-from'),
require('@babel/plugin-proposal-logical-assignment-operators'),
[require('@babel/plugin-proposal-optional-chaining'), { loose: false }],
[
require('@babel/plugin-proposal-pipeline-operator'),
{ proposal: 'minimal' }
],
[
require('@babel/plugin-proposal-nullish-coalescing-operator'),
{ loose: false }
],
require('@babel/plugin-proposal-do-expressions'),
// Stage 2
[require('@babel/plugin-proposal-decorators'), { legacy: true }],
require('@babel/plugin-proposal-function-sent'),
require('@babel/plugin-proposal-export-namespace-from'),
require('@babel/plugin-proposal-numeric-separator'),
require('@babel/plugin-proposal-throw-expressions'),
// Stage 3
require('@babel/plugin-syntax-dynamic-import'),
require('@babel/plugin-syntax-import-meta'),
[require('@babel/plugin-proposal-class-properties'), { loose: true }],
require('@babel/plugin-proposal-json-strings'),
require('@babel/plugin-transform-runtime'),
...(development ? developmentPlugins : productionPlugins)
]
};
};
webpack.config.base.js
import path from 'path';
import webpack from 'webpack';
import fs from 'fs';
import { dependencies as externals } from './app/package.json';
export default {
externals: [
...Object.keys(externals || {})
],
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
},
'ts-loader'
]
}
]
},
output: {
path: path.join(__dirname, 'app'),
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
modules: [path.join(__dirname, 'app'), 'node_modules']
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'production'
}),
new webpack.NamedModulesPlugin()
]
};
答案 0 :(得分:0)
您的错误表明,您的生成系统未将ES模块语法转换为CommonJS语法。 Electron不容易以本机方式支持ES模块(一些不错的链接总结如下:Link,Link,Link,Link),因此它无法解释{{ 1}}语句。
当您根据tsconfig.json将.ts文件转换为import
时,带有ES模块的旧.js文件似乎是关键所在。在.babelrc中,您像这样配置@babel/preset-env:
"target": "es5"
我的猜测是没有移植到CommonJS,因为您指定了Electron [
"@babel/preset-env", {
"targets": { "electron": "6.0.2" },
"corejs": "2",
"useBuiltIns": "usage"
}
]
作为目标,它映射到非常不错的支持ES模块的Chromium版本-请参见设置modules: auto
和{{3} }以获取更多信息。
当您为渲染器设置自定义Babel设置时,我会将您的问题进一步隔离到主要流程中:
6.0.2
,webpack.config.renderer.dev.js
:
babel-loader
每当您设置这些use: {
loader: 'babel-loader',
options: {
...
}
}
时,options
都将被完全忽略,并且.babelrc
中的所有内容都将在webpack构建过程中获取,包括babel转换。因此,对于渲染器配置,Babel应该采用其默认选项,包括转换为CommonJS语法,以有效消除渲染器过程中的导入错误。
我们必须带Babel才能将您的主要流程.js文件转换为CommonJS语法。最简单的方法是更改what it means选项:
options
您可以在主进程的babel配置中添加此设置,也可以直接在主webpack配置中的[
"@babel/env", {
...
"modules": "cjs"
}
],
选项中添加此设置(类似于渲染器webpack.config)。请记住,如果要进行后者,则必须在选项中添加babel-loader
中的所有设置。作为.babelrc
选项的替代方法,您也可以尝试使用modules插件。
P,那比预期的要长一些。希望您仍然清醒,并能有所帮助。祝你好运!